{"created": 1783440013.6965806, "duration": 5920.54901432991, "exitcode": 2, "root": "/workspace/source/test/e2e", "environment": {}, "summary": {"passed": 37, "failed": 5, "total": 42, "collected": 42}, "collectors": [{"nodeid": "explainer/test_art_explainer.py", "outcome": "skipped", "result": [], "longrepr": "('/workspace/source/test/e2e/explainer/test_art_explainer.py', 38, 'Skipped: ODH does not support art explainer at the moment')"}, {"nodeid": "predictor/test_grpc.py", "outcome": "skipped", "result": [], "longrepr": "('/workspace/source/test/e2e/predictor/test_grpc.py', 35, 'Skipped: Not testable in ODH at the moment')"}, {"nodeid": "predictor/test_torchserve.py", "outcome": "skipped", "result": [], "longrepr": "('/workspace/source/test/e2e/predictor/test_torchserve.py', 34, 'Skipped: ODH does not support torchserve at the moment')"}], "tests": [{"nodeid": "llmisvc/test_gateway_section_name.py::test_gateway_section_name_propagation[cluster_single_node-cluster_cpu-with-section-name]", "lineno": 131, "outcome": "passed", "keywords": ["test_gateway_section_name_propagation[with-section-name]", "parametrize", "llmd_simulator", "cluster_single_node", "cluster_cpu", "llminferenceservice", "pytestmark", "with-section-name", "test_gateway_section_name.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.0013742760020249989, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 12.101968494000175, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0008053240017034113, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-scheduler-with-precise-prefix-cache-inline-config-workload-llmd-simulator-kvcache]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-precise-prefix-cache-inline-config-workload-llmd-simulator-kvcache]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-scheduler-with-precise-prefix-cache-inline-config-workload-llmd-simulator-kvcache", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.37916033399960725, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 115.56402256900037, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.003397107000637334, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_gateway_section_name.py::test_gateway_section_name_propagation[cluster_single_node-cluster_cpu-without-section-name]", "lineno": 131, "outcome": "passed", "keywords": ["test_gateway_section_name_propagation[without-section-name]", "parametrize", "llmd_simulator", "cluster_single_node", "cluster_cpu", "llminferenceservice", "pytestmark", "without-section-name", "test_gateway_section_name.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.0004562739995890297, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 24.967666035001457, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0008037940024223644, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_auth.py::test_llm_auth_enabled_requires_token[cluster_cpu-cluster_single_node-auth-enabled-default]", "lineno": 221, "outcome": "passed", "keywords": ["test_llm_auth_enabled_requires_token[auth-enabled-default]", "parametrize", "auth", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "auth-enabled-default", "test_llm_auth.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.3975846720022673, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 197.40356503199655, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0032956319992081262, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-llmd-simulator0]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-llmd-simulator0]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator0", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.09235303400055273, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 63.299967430000834, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0021809300014865585, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-llmd-simulator1]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-llmd-simulator1]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "llmd_simulator", "model_routing", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator1", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.17100638299962156, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 138.83188290999897, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0029772439993394073, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_auth.py::test_llm_auth_invalid_token_rejected[cluster_cpu-cluster_single_node-auth-invalid-token]", "lineno": 380, "outcome": "passed", "keywords": ["test_llm_auth_invalid_token_rejected[auth-invalid-token]", "parametrize", "auth", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "auth-invalid-token", "test_llm_auth.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.2929339269976481, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 155.93153551100113, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.002579622003395343, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-llmd-simulator2]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-llmd-simulator2]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "llmd_simulator", "model_routing", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator2", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.2571824139995442, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 144.34613922100107, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.003158224000799237, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_auth.py::test_llm_auth_disabled_no_token_required[cluster_cpu-cluster_single_node-auth-disabled]", "lineno": 511, "outcome": "passed", "keywords": ["test_llm_auth_disabled_no_token_required[auth-disabled]", "parametrize", "auth", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "auth-disabled", "test_llm_auth.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.6548278560003382, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 165.4370619830006, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.002223763000074541, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf0]", "lineno": 244, "outcome": "failed", "keywords": ["test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf0]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "model_routing", "lora", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf0", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.30834770599904004, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 993.9517626300003, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))"}, "traceback": [{"path": "llmisvc/test_llm_inference_service.py", "lineno": 816, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1119, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1215, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError"}], "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17a1de10>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17a1de10>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n>           response = conn.getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:534: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17a1de10>\n\n    def getresponse(  # type: ignore[override]\n        self,\n    ) -> HTTPResponse:\n        \"\"\"\n        Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an instance of HTTPResponse or of whatever object is returned by the response_class variable.\n    \n        If a request has not been sent or if a previous response has not be handled, ResponseNotReady is raised. If the HTTP response indicates that the connection should be closed, then it will be closed before the response is returned. When the connection is closed, the underlying socket is closed.\n        \"\"\"\n        # Raise the same error as http.client.HTTPConnection\n        if self._response_options is None:\n            raise ResponseNotReady()\n    \n        # Reset this attribute for being used again.\n        resp_options = self._response_options\n        self._response_options = None\n    \n        # Since the connection's timeout value may have been updated\n        # we need to set the timeout on the socket.\n        self.sock.settimeout(self.timeout)\n    \n        # This is needed here to avoid circular import errors\n        from .response import HTTPResponse\n    \n        # Save a reference to the shutdown function before ownership is passed\n        # to httplib_response\n        # TODO should we implement it everywhere?\n        _shutdown = getattr(self.sock, \"shutdown\", None)\n    \n        # Get the response from http.client.HTTPConnection\n>       httplib_response = super().getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connection.py:571: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17a1de10>\n\n    def getresponse(self):\n        \"\"\"Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an\n        instance of HTTPResponse or of whatever object is returned by\n        the response_class variable.\n    \n        If a request has not been sent or if a previous response has\n        not be handled, ResponseNotReady is raised.  If the HTTP\n        response indicates that the connection should be closed, then\n        it will be closed before the response is returned.  When the\n        connection is closed, the underlying socket is closed.\n        \"\"\"\n    \n        # if a prior response has been completed, then forget about it.\n        if self.__response and self.__response.isclosed():\n            self.__response = None\n    \n        # if a prior response exists, then it must be completed (otherwise, we\n        # cannot read this response's header to determine the connection-close\n        # behavior)\n        #\n        # note: if a prior response existed, but was connection-close, then the\n        # socket and response were made independent of this HTTPConnection\n        # object since a new request requires that we open a whole new\n        # connection\n        #\n        # this means the prior response had one of two states:\n        #   1) will_close: this connection was reset and the prior socket and\n        #                  response operate independently\n        #   2) persistent: the response was retained and we await its\n        #                  isclosed() status to become true.\n        #\n        if self.__state != _CS_REQ_SENT or self.__response:\n            raise ResponseNotReady(self.__state)\n    \n        if self.debuglevel > 0:\n            response = self.response_class(self.sock, self.debuglevel,\n                                           method=self._method)\n        else:\n            response = self.response_class(self.sock, method=self._method)\n    \n        try:\n            try:\n>               response.begin()\n\n/usr/lib64/python3.11/http/client.py:1395: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f1d17ddef20>\n\n    def begin(self):\n        if self.headers is not None:\n            # we've already started reading the response\n            return\n    \n        # read until we get a non-100 response\n        while True:\n>           version, status, reason = self._read_status()\n\n/usr/lib64/python3.11/http/client.py:325: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f1d17ddef20>\n\n    def _read_status(self):\n>       line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n\n/usr/lib64/python3.11/http/client.py:286: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <socket.SocketIO object at 0x7f1d17ddf820>\nb = <memory at 0x7f1d17bbf100>\n\n    def readinto(self, b):\n        \"\"\"Read up to len(b) bytes into the writable buffer *b* and return\n        the number of bytes read.  If the socket is non-blocking and no bytes\n        are available, None is returned.\n    \n        If *b* is non-empty, a 0 return value indicates that the connection\n        was shutdown at the other end.\n        \"\"\"\n        self._checkClosed()\n        self._checkReadable()\n        if self._timeout_occurred:\n            raise OSError(\"cannot read from timed out object\")\n        while True:\n            try:\n>               return self._sock.recv_into(b)\nE               TimeoutError: timed out\n\n/usr/lib64/python3.11/socket.py:718: TimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n>           response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:787: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17a1de10>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17a1de10>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n            response = conn.getresponse()\n        except (BaseSSLError, OSError) as e:\n>           self._raise_timeout(err=e, url=url, timeout_value=read_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:536: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nerr = TimeoutError('timed out'), url = '/v1/completions', timeout_value = 60\n\n    def _raise_timeout(\n        self,\n        err: BaseSSLError | OSError | SocketTimeout,\n        url: str,\n        timeout_value: _TYPE_TIMEOUT | None,\n    ) -> None:\n        \"\"\"Is the error actually a timeout? Will raise a ReadTimeout or pass\"\"\"\n    \n        if isinstance(err, SocketTimeout):\n>           raise ReadTimeoutError(\n                self, url, f\"Read timed out. (read timeout={timeout_value})\"\n            ) from err\nE           urllib3.exceptions.ReadTimeoutError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:367: ReadTimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <requests.adapters.HTTPAdapter object at 0x7f1d179a1c10>\nrequest = <PreparedRequest [POST]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n>           resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:667: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=7, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=6, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=5, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=4, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=3, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=2, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=1, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\nmethod = 'POST', url = '/v1/completions'\nbody = b'{\"model\": \"publishers/kserve-ci-e2e-test/models/lora-adapter-1\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-aliv...lication/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'Content-Length': '107'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n>           retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:841: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nmethod = 'POST', url = '/v1/completions', response = None\nerror = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\n_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d179a0bd0>\n_stacktrace = <traceback object at 0x7f1d17a1d140>\n\n    def increment(\n        self,\n        method: str | None = None,\n        url: str | None = None,\n        response: BaseHTTPResponse | None = None,\n        error: Exception | None = None,\n        _pool: ConnectionPool | None = None,\n        _stacktrace: TracebackType | None = None,\n    ) -> Self:\n        \"\"\"Return a new Retry object with incremented retry counters.\n    \n        :param response: A response object, or None, if the server did not\n            return a response.\n        :type response: :class:`~urllib3.response.BaseHTTPResponse`\n        :param Exception error: An error encountered during the request, or\n            None if the response was received successfully.\n    \n        :return: A new ``Retry`` object.\n        \"\"\"\n        if self.total is False and error:\n            # Disabled, indicate to re-raise the error.\n            raise reraise(type(error), error, _stacktrace)\n    \n        total = self.total\n        if total is not None:\n            total -= 1\n    \n        connect = self.connect\n        read = self.read\n        redirect = self.redirect\n        status_count = self.status\n        other = self.other\n        cause = \"unknown\"\n        status = None\n        redirect_location = None\n    \n        if error and self._is_connection_error(error):\n            # Connect retry?\n            if connect is False:\n                raise reraise(type(error), error, _stacktrace)\n            elif connect is not None:\n                connect -= 1\n    \n        elif error and self._is_read_error(error):\n            # Read retry?\n            if read is False or method is None or not self._is_method_retryable(method):\n                raise reraise(type(error), error, _stacktrace)\n            elif read is not None:\n                read -= 1\n    \n        elif error:\n            # Other retry?\n            if other is not None:\n                other -= 1\n    \n        elif response and response.get_redirect_location():\n            # Redirect retry?\n            if redirect is not None:\n                redirect -= 1\n            cause = \"too many redirects\"\n            response_redirect_location = response.get_redirect_location()\n            if response_redirect_location:\n                redirect_location = response_redirect_location\n            status = response.status\n    \n        else:\n            # Incrementing because of a server error like a 500 in\n            # status_forcelist and the given method is in the allowed_methods\n            cause = ResponseError.GENERIC_ERROR\n            if response and response.status:\n                if status_count is not None:\n                    status_count -= 1\n                cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)\n                status = response.status\n    \n        history = self.history + (\n            RequestHistory(method, url, error, status, redirect_location),\n        )\n    \n        new_retry = self.new(\n            total=total,\n            connect=connect,\n            read=read,\n            redirect=redirect,\n            status=status_count,\n            other=other,\n            history=history,\n        )\n    \n        if new_retry.is_exhausted():\n            reason = error or ResponseError(cause)\n>           raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]\nE           urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/util/retry.py:519: MaxRetryError\n\nDuring handling of the above exception, another exception occurred:\n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n>               response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n\nllmisvc/test_llm_inference_service.py:1095: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/v1/completions'\n\n    def post_with_retry(\n        url: str,\n        *,\n        headers: Dict = None,\n        json_data: Union[Dict, List] = None,\n        data: Union[str, bytes] = None,\n        stream: bool = False,\n        timeout: float = None,\n        total_retries: int = DEFAULT_RETRY_TOTAL,\n        backoff_factor: float = DEFAULT_RETRY_BACKOFF_FACTOR,\n        retry_status_codes=DEFAULT_RETRY_STATUS_CODES,\n    ) -> requests.Response:\n        \"\"\"\n        Send POST request with retries for transient HTTP and network failures.\n        \"\"\"\n        if json_data is not None and data is not None:\n            raise ValueError(\"Only one of json_data or data can be provided.\")\n    \n        with _retry_session(\n            [\"POST\"], total_retries, backoff_factor, retry_status_codes\n        ) as session:\n>           return session.post(\n                url,\n                json=json_data,\n                data=data,\n                headers=headers,\n                stream=stream,\n                timeout=timeout,\n            )\n\ncommon/http_retry.py:70: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d179caf90>\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/v1/completions'\ndata = None\njson = {'max_tokens': 20, 'model': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'prompt': 'KServe is a'}\nkwargs = {'headers': {'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1'}, 'stream': False, 'timeout': 60}\n\n    def post(self, url, data=None, json=None, **kwargs):\n        r\"\"\"Sends a POST request. Returns :class:`Response` object.\n    \n        :param url: URL for the new :class:`Request` object.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the :class:`Request`.\n        :param \\*\\*kwargs: Optional arguments that ``request`` takes.\n        :rtype: requests.Response\n        \"\"\"\n    \n>       return self.request(\"POST\", url, data=data, json=json, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:637: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d179caf90>, method = 'POST'\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/v1/completions'\nparams = None, data = None\nheaders = {'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1'}\ncookies = None, files = None, auth = None, timeout = 60, allow_redirects = True\nproxies = {}, hooks = None, stream = False, verify = None, cert = None\njson = {'max_tokens': 20, 'model': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1', 'prompt': 'KServe is a'}\n\n    def request(\n        self,\n        method,\n        url,\n        params=None,\n        data=None,\n        headers=None,\n        cookies=None,\n        files=None,\n        auth=None,\n        timeout=None,\n        allow_redirects=True,\n        proxies=None,\n        hooks=None,\n        stream=None,\n        verify=None,\n        cert=None,\n        json=None,\n    ):\n        \"\"\"Constructs a :class:`Request <Request>`, prepares it and sends it.\n        Returns :class:`Response <Response>` object.\n    \n        :param method: method for the new :class:`Request` object.\n        :param url: URL for the new :class:`Request` object.\n        :param params: (optional) Dictionary or bytes to be sent in the query\n            string for the :class:`Request`.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the\n            :class:`Request`.\n        :param headers: (optional) Dictionary of HTTP Headers to send with the\n            :class:`Request`.\n        :param cookies: (optional) Dict or CookieJar object to send with the\n            :class:`Request`.\n        :param files: (optional) Dictionary of ``'filename': file-like-objects``\n            for multipart encoding upload.\n        :param auth: (optional) Auth tuple or callable to enable\n            Basic/Digest/Custom HTTP Auth.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple\n        :param allow_redirects: (optional) Set to True by default.\n        :type allow_redirects: bool\n        :param proxies: (optional) Dictionary mapping protocol or protocol and\n            hostname to the URL of the proxy.\n        :param hooks: (optional) Dictionary mapping hook name to one event or\n            list of events, event must be callable.\n        :param stream: (optional) whether to immediately download the response\n            content. Defaults to ``False``.\n        :param verify: (optional) Either a boolean, in which case it controls whether we verify\n            the server's TLS certificate, or a string, in which case it must be a path\n            to a CA bundle to use. Defaults to ``True``. When set to\n            ``False``, requests will accept any TLS certificate presented by\n            the server, and will ignore hostname mismatches and/or expired\n            certificates, which will make your application vulnerable to\n            man-in-the-middle (MitM) attacks. Setting verify to ``False``\n            may be useful during local development or testing.\n        :param cert: (optional) if String, path to ssl client cert file (.pem).\n            If Tuple, ('cert', 'key') pair.\n        :rtype: requests.Response\n        \"\"\"\n        # Create the Request.\n        req = Request(\n            method=method.upper(),\n            url=url,\n            headers=headers,\n            files=files,\n            data=data or {},\n            json=json,\n            params=params or {},\n            auth=auth,\n            cookies=cookies,\n            hooks=hooks,\n        )\n        prep = self.prepare_request(req)\n    \n        proxies = proxies or {}\n    \n        settings = self.merge_environment_settings(\n            prep.url, proxies, stream, verify, cert\n        )\n    \n        # Send the request.\n        send_kwargs = {\n            \"timeout\": timeout,\n            \"allow_redirects\": allow_redirects,\n        }\n        send_kwargs.update(settings)\n>       resp = self.send(prep, **send_kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:589: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d179caf90>\nrequest = <PreparedRequest [POST]>\nkwargs = {'cert': None, 'proxies': OrderedDict(), 'stream': False, 'timeout': 60, ...}\nallow_redirects = True, stream = False, hooks = {'response': []}\nadapter = <requests.adapters.HTTPAdapter object at 0x7f1d179a1c10>\nstart = 1783434646.1162572\n\n    def send(self, request, **kwargs):\n        \"\"\"Send a given PreparedRequest.\n    \n        :rtype: requests.Response\n        \"\"\"\n        # Set defaults that the hooks can utilize to ensure they always have\n        # the correct parameters to reproduce the previous request.\n        kwargs.setdefault(\"stream\", self.stream)\n        kwargs.setdefault(\"verify\", self.verify)\n        kwargs.setdefault(\"cert\", self.cert)\n        if \"proxies\" not in kwargs:\n            kwargs[\"proxies\"] = resolve_proxies(request, self.proxies, self.trust_env)\n    \n        # It's possible that users might accidentally send a Request object.\n        # Guard against that specific failure case.\n        if isinstance(request, Request):\n            raise ValueError(\"You can only send PreparedRequests.\")\n    \n        # Set up variables needed for resolve_redirects and dispatching of hooks\n        allow_redirects = kwargs.pop(\"allow_redirects\", True)\n        stream = kwargs.get(\"stream\")\n        hooks = request.hooks\n    \n        # Get the appropriate adapter to use\n        adapter = self.get_adapter(url=request.url)\n    \n        # Start time (approximately) of the request\n        start = preferred_clock()\n    \n        # Send the request\n>       r = adapter.send(request, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:703: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.adapters.HTTPAdapter object at 0x7f1d179a1c10>\nrequest = <PreparedRequest [POST]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n            resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n    \n        except (ProtocolError, OSError) as err:\n            raise ConnectionError(err, request=request)\n    \n        except MaxRetryError as e:\n            if isinstance(e.reason, ConnectTimeoutError):\n                # TODO: Remove this in 3.0.0: see #2811\n                if not isinstance(e.reason, NewConnectionError):\n                    raise ConnectTimeout(e, request=request)\n    \n            if isinstance(e.reason, ResponseError):\n                raise RetryError(e, request=request)\n    \n            if isinstance(e.reason, _ProxyError):\n                raise ProxyError(e, request=request)\n    \n            if isinstance(e.reason, _SSLError):\n                # This branch is for urllib3 v1.22 and later.\n                raise SSLError(e, request=request)\n    \n>           raise ConnectionError(e, request=request)\nE           requests.exceptions.ConnectionError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:700: ConnectionError\n\nThe above exception was the direct cause of the following exception:\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-single-cpu', 'model-fb-opt-125m-with-lora-hf'], prompt='KServe is a', ...opt-125m-with-lora-hf-a7886ead'}]},\n 'status': None}, model_name='publishers/kserve-ci-e2e-test/models/lora-adapter-1')\n\n    @pytest.mark.llminferenceservice\n    @pytest.mark.asyncio(loop_scope=\"session\")\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-gateway-ref\",\n                        \"router-with-managed-route\",\n                        \"model-fb-opt-125m\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=create_response_assertion(with_field=\"choices\"),\n                    expected_gateway=ROUTER_GATEWAYS[0],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[0]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-custom-route-timeout\",\n                        \"scheduler-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"custom-route-timeout-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-refs\",\n                        \"scheduler-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"router-with-refs-test\",\n                    expected_gateway=ROUTER_GATEWAYS[0],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[0]],\n                            routes=[ROUTER_ROUTES[0], ROUTER_ROUTES[1]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\"router-managed\", \"workload-pd-cpu\", \"model-fb-opt-125m\"],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-custom-route-timeout-pd\",\n                        \"scheduler-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    service_name=\"custom-route-timeout-pd-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-refs-pd\",\n                        \"scheduler-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    service_name=\"router-with-refs-pd-test\",\n                    response_assertion=assert_200_with_choices,\n                    expected_gateway=ROUTER_GATEWAYS[1],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[1]],\n                            routes=[ROUTER_ROUTES[2], ROUTER_ROUTES[3]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-dp-ep-gpu\",\n                        \"workload-dp-ep-prefill-gpu\",\n                        \"model-deepseek-v2-lite\",\n                    ],\n                    prompt=\"Delve into the multifaceted implications of a fully disaggregated cloud architecture, specifically \"\n                    \"where the compute plane (P) and the data plane (D) are independently deployed and managed for a \"\n                    \"geographically distributed, high-throughput, low-latency microservices ecosystem. Beyond the \"\n                    \"fundamental challenges of network latency and data consistency, elaborate on the advanced \"\n                    \"considerations and trade-offs inherent in such a setup: 1. Network Architecture and Protocols: \"\n                    \"How would the network fabric and underlying protocols (e.g., RDMA, custom transport layers) need to \"\n                    \"evolve to support optimal performance and minimize inter-plane communication overhead, especially for \"\n                    \"synchronous operations? Discuss the role of network programmability (e.g., SDN, P4) in dynamically \"\n                    \"optimizing routing and traffic flow between P and D. 2. Advanced Data Consistency and Durability: \"\n                    \"Explore sophisticated data consistency models (e.g., causal consistency, strong eventual consistency) \"\n                    \"and their applicability in balancing performance and data integrity across a globally distributed data plane. \"\n                    \"Detail strategies for ensuring data durability and fault tolerance, including multi-region replication, \"\n                    \"intelligent partitioning, and recovery mechanisms in the event of partial or full plane failures. \"\n                    \"3. Dynamic Resource Orchestration and Cost Optimization: Analyze how an orchestration layer would intelligently \"\n                    \"manage the independent scaling of compute (P) and data (D) resources, considering fluctuating workloads, \"\n                    \"cost efficiency, and performance targets (e.g., using predictive analytics for resource provisioning). \"\n                    \"Discuss mechanisms for dynamically reallocating compute nodes to different data partitions based on \"\n                    \"workload patterns and data locality, potentially involving live migration strategies. \"\n                    \"4. Security and Compliance in a Distributed Landscape: Address the enhanced security perimeter \"\n                    \"challenges, including securing communication channels between P and D (encryption in transit, mutual TLS), \"\n                    \"fine-grained access control to data at rest and in motion, and identity management across disaggregated \"\n                    \"components. Discuss how such an architecture impacts compliance with regulatory frameworks (e.g., GDPR, HIPAA) \"\n                    \"concerning data sovereignty, privacy, and auditability. 5. Operational Complexity and Observability: \"\n                    \"Examine the increased complexity in monitoring, logging, and tracing across highly decoupled compute and \"\n                    \"data planes. What specialized tooling and practices (e.g., distributed tracing with OpenTelemetry, advanced AIOps) \"\n                    \"would be essential? How would incident response and troubleshooting differ in this disaggregated environment \"\n                    \"compared to traditional integrated systems? Consider the challenges of pinpointing root causes across \"\n                    \"independent failures. 6. Real-world Applicability and Future Trends: Identify specific industries \"\n                    \"or use cases (e.g., high-frequency trading, IoT edge processing, large language model inference) \"\n                    \"where the benefits of P/D disaggregation would strongly outweigh its complexities. \"\n                    \"Conclude by speculating on emerging technologies or paradigms (e.g., serverless compute functions \"\n                    \"directly interacting with object storage, in-memory disaggregation) that could further drive or \"\n                    \"transform P/D disaggregation in cloud computing.\",\n                    max_tokens=2000,\n                ),\n                marks=[\n                    pytest.mark.cluster_gpu,\n                    pytest.mark.cluster_nvidia,\n                    pytest.mark.cluster_nvidia_roce,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-no-scheduler\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"What is KServe?\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.no_scheduler,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-simulated-dp-ep-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"This test simulates DP+EP that can run on CPU, the idea is to test the LWS-based deployment, \"\n                    \"but without the resources requirements for DP+EP (GPUs and ROCe/IB).\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_multi_node],\n            ),\n            # Scheduler config tests\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-inline-config\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-inline-config-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            # Chat completions endpoint coverage\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                        \"model-qwen2.5-0.5b\",\n                    ],\n                    model_name=\"Qwen/Qwen2.5-0.5B-Instruct\",\n                    endpoint=\"/v1/chat/completions\",\n                    prompt=\"What is KServe?\",\n                    payload_formatter=chat_completions_payload,\n                    response_assertion=create_response_assertion(with_field=\"choices\"),\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-configmap-ref\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-configmap-ref-test\",\n                    before_test=[create_scheduler_configmap],\n                    after_test=[delete_scheduler_configmap],\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-replicas\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-ha-replicas-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-custom-template\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-custom-template-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            # Scheduler v0.6 \u2192 v0.7 migration tests.\n            # Deploy v0.6-style configs and verify the controller migrates them\n            # so the v0.7 scheduler boots successfully.\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-v06-pd-config-migration\",\n                        \"workload-llmd-simulator-pd\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-v06-pd-migration-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-v06-nonzero-threshold-migration\",\n                        \"workload-llmd-simulator-pd\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-v06-threshold-migration-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Precise prefix KV cache routing test\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-precise-prefix-cache-inline-config\",\n                        \"workload-llmd-simulator-kvcache\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"precise-prefix-cache-test\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Models endpoint coverage\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/models\",\n                    response_assertion=create_response_assertion(with_field=\"data\"),\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/completions\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\"facebook/opt-125m\"),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                    peers=[\n                        TestCase(\n                            base_refs=[\n                                \"router-managed\",\n                                \"workload-llmd-simulator\",\n                                \"model-qwen2.5-0.5b\",\n                            ],\n                            endpoint=\"/v1/completions\",\n                            prompt=\"KServe is a\",\n                            payload_formatter=completions_payload,\n                            response_assertion=assert_model_field_matches(\n                                \"Qwen/Qwen2.5-0.5B-Instruct\"\n                            ),\n                            url_getter=get_model_routing_url,\n                            extra_headers={\n                                MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/Qwen/Qwen2.5-0.5B-Instruct\",\n                            },\n                        ),\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.model_routing,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/chat/completions\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/chat/completions\",\n                    prompt=\"What is KServe?\",\n                    payload_formatter=chat_completions_payload,\n                    response_assertion=assert_model_field_matches(\"facebook/opt-125m\"),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                    peers=[\n                        TestCase(\n                            base_refs=[\n                                \"router-managed\",\n                                \"workload-llmd-simulator\",\n                                \"model-qwen2.5-0.5b\",\n                            ],\n                            endpoint=\"/v1/chat/completions\",\n                            prompt=\"What is KServe?\",\n                            payload_formatter=chat_completions_payload,\n                            response_assertion=assert_model_field_matches(\n                                \"Qwen/Qwen2.5-0.5B-Instruct\"\n                            ),\n                            url_getter=get_model_routing_url,\n                            extra_headers={\n                                MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/Qwen/Qwen2.5-0.5B-Instruct\",\n                            },\n                        ),\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.model_routing,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 LoRA adapter\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m-with-lora-hf\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    model_name=f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\"\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    },\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.model_routing,\n                    pytest.mark.lora,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/models (base + LoRA)\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m-with-lora-hf\",\n                    ],\n                    endpoint=\"/v1/models\",\n                    response_assertion=assert_models_contains(\n                        \"facebook/opt-125m\",\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                        \"lora-adapter-1\",\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.model_routing,\n                    pytest.mark.lora,\n                ],\n            ),\n            # PVC storage tests -- validate direct PVC volume mount with real vLLM serving\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    response_assertion=assert_200_with_choices,\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    response_assertion=assert_200_with_choices,\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-simulated-dp-ep-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_multi_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_inference_service(test_case: TestCase):  # noqa: F811\n        inject_k8s_proxy()\n    \n        kserve_client = KServeClient(\n            config_file=os.environ.get(\"KUBECONFIG\", \"~/.kube/config\"),\n            client_configuration=client.Configuration(),\n        )\n    \n        service_name = test_case.llm_service.metadata.name\n        if not test_case.llm_service.metadata.annotations:\n            test_case.llm_service.metadata.annotations = {}\n    \n        test_case.llm_service.metadata.annotations[\n            \"security.opendatahub.io/enable-auth\"\n        ] = \"false\"\n        prefix = test_case.log_prefix\n    \n        test_failed = False\n        try:\n            print(f\"{prefix} Creating LLMInferenceService {service_name}\")\n            create_llmisvc(kserve_client, test_case.llm_service)\n            print(f\"{prefix} Waiting for LLMInferenceService {service_name} to be ready\")\n            wait_for_llm_isvc_ready(\n                kserve_client, test_case.llm_service, test_case.wait_timeout\n            )\n            print(f\"{prefix} Waiting for model response from {service_name}\")\n>           wait_for_model_response(\n                kserve_client,\n                test_case,\n                test_case.wait_timeout,\n                extra_headers=test_case.extra_headers,\n            )\n\nllmisvc/test_llm_inference_service.py:816: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f1d18ca7f50>, TestCase(base_refs=['router-managed', 'workload-sin...5m-with-lora-hf-a7886ead'}]},\n 'status': None}, model_name='publishers/kserve-ci-e2e-test/models/lora-adapter-1'), 900)\nkwargs = {'extra_headers': {'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1'}}\nfunc_name = 'wait_for_model_response'\ntimestamp_start = '2026-07-07T14:30:46.101641', start_time = 1783434646.1019633\nduration = 904.638260602951, timestamp_end = '2026-07-07T14:45:50.740227'\n\n    @functools.wraps(func)\n    def wrapper(*args, **kwargs):\n        func_name = func.__name__\n    \n        timestamp_start = datetime.now().isoformat()\n        logger.info(\n            f\"[{func_name}] [{timestamp_start}] start - args={args}, kwargs={kwargs}\"\n        )\n        start_time = time.time()\n    \n        try:\n>           result = func(*args, **kwargs)\n\nllmisvc/logging.py:40: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f1d18ca7f50>\ntest_case = TestCase(base_refs=['router-managed', 'workload-single-cpu', 'model-fb-opt-125m-with-lora-hf'], prompt='KServe is a', ...opt-125m-with-lora-hf-a7886ead'}]},\n 'status': None}, model_name='publishers/kserve-ci-e2e-test/models/lora-adapter-1')\ntimeout_seconds = 900\nextra_headers = {'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/lora-adapter-1'}\n\n    @log_execution\n    def wait_for_model_response(\n        kserve_client: KServeClient,\n        test_case: TestCase,  # noqa: F811\n        timeout_seconds: int = 900,\n        extra_headers: Optional[Dict[str, str]] = None,\n    ) -> str:\n        def get_successful_response():\n            try:\n                if test_case.url_getter:\n                    service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n                else:\n                    service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n            except Exception as e:\n                raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n            model_url = service_url + test_case.endpoint\n    \n            headers = {\"Content-Type\": \"application/json\"}\n            if extra_headers:\n                headers.update(extra_headers)\n    \n            if test_case.payload_formatter is not None:\n                test_payload = test_case.payload_formatter(test_case)\n            elif test_case.prompt is not None:\n                test_payload = {\n                    \"model\": test_case.model_name\n                    if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                    else extra_headers[MODEL_ROUTING_HEADER],\n                    \"prompt\": test_case.prompt,\n                    \"max_tokens\": test_case.max_tokens,\n                }\n            else:\n                test_payload = None\n    \n            logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n            try:\n                if test_payload is not None:\n                    response = post_with_retry(\n                        model_url,\n                        headers=headers,\n                        json_data=test_payload,\n                        timeout=test_case.response_timeout,\n                    )\n                else:\n                    response = get_with_retry(\n                        model_url,\n                        headers=headers,\n                        timeout=test_case.response_timeout,\n                    )\n            except Exception as e:\n                logger.error(f\"\u274c Failed to call model: {e}\")\n                raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\n    \n            logger.info(f\"Model response is {response.status_code}: {response.text[:500]}\")\n    \n            if 200 <= response.status_code < 300:\n                return response\n            raise AssertionError(\n                f\"Service returned {response.status_code}: {response.text}\"\n            )\n    \n>       response = wait_for(get_successful_response, timeout=timeout_seconds, interval=5.0)\n\nllmisvc/test_llm_inference_service.py:1119: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_model_response.<locals>.get_successful_response at 0x7f1d17b70cc0>\ntimeout = 900, interval = 5.0\n\n    def wait_for(\n        assertion_fn: Callable[[], Any], timeout: float = 5.0, interval: float = 0.1\n    ) -> Any:\n        \"\"\"Wait for the assertion to succeed within timeout.\"\"\"\n        deadline = time.time() + timeout\n        last_msg = None\n        while True:\n            try:\n>               return assertion_fn()\n\nllmisvc/test_llm_inference_service.py:1215: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n                response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n            else:\n                response = get_with_retry(\n                    model_url,\n                    headers=headers,\n                    timeout=test_case.response_timeout,\n                )\n        except Exception as e:\n            logger.error(f\"\u274c Failed to call model: {e}\")\n>           raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\nE           AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\nllmisvc/test_llm_inference_service.py:1109: AssertionError"}, "teardown": {"duration": 0.002816836000420153, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-with-gateway-ref-router-with-managed-route-model-fb-opt-125m-workload-llmd-simulator]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-with-gateway-ref-router-with-managed-route-model-fb-opt-125m-workload-llmd-simulator]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "llmd_simulator", "custom_gateway", "__wrapped__", "pytestmark", "router-with-gateway-ref-router-with-managed-route-model-fb-opt-125m-workload-llmd-simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.6891732629992475, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 42.168287993001286, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0018534419978095684, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-single-cpu-model-fb-opt-125m]", "lineno": 244, "outcome": "failed", "keywords": ["test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.180201617997227, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 1032.2499392030004, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))"}, "traceback": [{"path": "llmisvc/test_llm_inference_service.py", "lineno": 816, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1119, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1215, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError"}], "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0db93dd0>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0db93dd0>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n>           response = conn.getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:534: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0db93dd0>\n\n    def getresponse(  # type: ignore[override]\n        self,\n    ) -> HTTPResponse:\n        \"\"\"\n        Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an instance of HTTPResponse or of whatever object is returned by the response_class variable.\n    \n        If a request has not been sent or if a previous response has not be handled, ResponseNotReady is raised. If the HTTP response indicates that the connection should be closed, then it will be closed before the response is returned. When the connection is closed, the underlying socket is closed.\n        \"\"\"\n        # Raise the same error as http.client.HTTPConnection\n        if self._response_options is None:\n            raise ResponseNotReady()\n    \n        # Reset this attribute for being used again.\n        resp_options = self._response_options\n        self._response_options = None\n    \n        # Since the connection's timeout value may have been updated\n        # we need to set the timeout on the socket.\n        self.sock.settimeout(self.timeout)\n    \n        # This is needed here to avoid circular import errors\n        from .response import HTTPResponse\n    \n        # Save a reference to the shutdown function before ownership is passed\n        # to httplib_response\n        # TODO should we implement it everywhere?\n        _shutdown = getattr(self.sock, \"shutdown\", None)\n    \n        # Get the response from http.client.HTTPConnection\n>       httplib_response = super().getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connection.py:571: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0db93dd0>\n\n    def getresponse(self):\n        \"\"\"Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an\n        instance of HTTPResponse or of whatever object is returned by\n        the response_class variable.\n    \n        If a request has not been sent or if a previous response has\n        not be handled, ResponseNotReady is raised.  If the HTTP\n        response indicates that the connection should be closed, then\n        it will be closed before the response is returned.  When the\n        connection is closed, the underlying socket is closed.\n        \"\"\"\n    \n        # if a prior response has been completed, then forget about it.\n        if self.__response and self.__response.isclosed():\n            self.__response = None\n    \n        # if a prior response exists, then it must be completed (otherwise, we\n        # cannot read this response's header to determine the connection-close\n        # behavior)\n        #\n        # note: if a prior response existed, but was connection-close, then the\n        # socket and response were made independent of this HTTPConnection\n        # object since a new request requires that we open a whole new\n        # connection\n        #\n        # this means the prior response had one of two states:\n        #   1) will_close: this connection was reset and the prior socket and\n        #                  response operate independently\n        #   2) persistent: the response was retained and we await its\n        #                  isclosed() status to become true.\n        #\n        if self.__state != _CS_REQ_SENT or self.__response:\n            raise ResponseNotReady(self.__state)\n    \n        if self.debuglevel > 0:\n            response = self.response_class(self.sock, self.debuglevel,\n                                           method=self._method)\n        else:\n            response = self.response_class(self.sock, method=self._method)\n    \n        try:\n            try:\n>               response.begin()\n\n/usr/lib64/python3.11/http/client.py:1395: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f4f0df690c0>\n\n    def begin(self):\n        if self.headers is not None:\n            # we've already started reading the response\n            return\n    \n        # read until we get a non-100 response\n        while True:\n>           version, status, reason = self._read_status()\n\n/usr/lib64/python3.11/http/client.py:325: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f4f0df690c0>\n\n    def _read_status(self):\n>       line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n\n/usr/lib64/python3.11/http/client.py:286: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <socket.SocketIO object at 0x7f4f0df698d0>\nb = <memory at 0x7f4f0dc1cac0>\n\n    def readinto(self, b):\n        \"\"\"Read up to len(b) bytes into the writable buffer *b* and return\n        the number of bytes read.  If the socket is non-blocking and no bytes\n        are available, None is returned.\n    \n        If *b* is non-empty, a 0 return value indicates that the connection\n        was shutdown at the other end.\n        \"\"\"\n        self._checkClosed()\n        self._checkReadable()\n        if self._timeout_occurred:\n            raise OSError(\"cannot read from timed out object\")\n        while True:\n            try:\n>               return self._sock.recv_into(b)\nE               TimeoutError: timed out\n\n/usr/lib64/python3.11/socket.py:718: TimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n>           response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:787: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0db93dd0>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0db93dd0>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n            response = conn.getresponse()\n        except (BaseSSLError, OSError) as e:\n>           self._raise_timeout(err=e, url=url, timeout_value=read_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:536: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nerr = TimeoutError('timed out')\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\ntimeout_value = 60\n\n    def _raise_timeout(\n        self,\n        err: BaseSSLError | OSError | SocketTimeout,\n        url: str,\n        timeout_value: _TYPE_TIMEOUT | None,\n    ) -> None:\n        \"\"\"Is the error actually a timeout? Will raise a ReadTimeout or pass\"\"\"\n    \n        if isinstance(err, SocketTimeout):\n>           raise ReadTimeoutError(\n                self, url, f\"Read timed out. (read timeout={timeout_value})\"\n            ) from err\nE           urllib3.exceptions.ReadTimeoutError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:367: ReadTimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <requests.adapters.HTTPAdapter object at 0x7f4f0db51a10>\nrequest = <PreparedRequest [POST]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n>           resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:667: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=7, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=6, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=5, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=4, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=3, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=2, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = RemoteDisconnected('Remote end closed connection without response')\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=1, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n>           retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:841: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nresponse = None\nerror = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\n_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0db53290>\n_stacktrace = <traceback object at 0x7f4f0db926c0>\n\n    def increment(\n        self,\n        method: str | None = None,\n        url: str | None = None,\n        response: BaseHTTPResponse | None = None,\n        error: Exception | None = None,\n        _pool: ConnectionPool | None = None,\n        _stacktrace: TracebackType | None = None,\n    ) -> Self:\n        \"\"\"Return a new Retry object with incremented retry counters.\n    \n        :param response: A response object, or None, if the server did not\n            return a response.\n        :type response: :class:`~urllib3.response.BaseHTTPResponse`\n        :param Exception error: An error encountered during the request, or\n            None if the response was received successfully.\n    \n        :return: A new ``Retry`` object.\n        \"\"\"\n        if self.total is False and error:\n            # Disabled, indicate to re-raise the error.\n            raise reraise(type(error), error, _stacktrace)\n    \n        total = self.total\n        if total is not None:\n            total -= 1\n    \n        connect = self.connect\n        read = self.read\n        redirect = self.redirect\n        status_count = self.status\n        other = self.other\n        cause = \"unknown\"\n        status = None\n        redirect_location = None\n    \n        if error and self._is_connection_error(error):\n            # Connect retry?\n            if connect is False:\n                raise reraise(type(error), error, _stacktrace)\n            elif connect is not None:\n                connect -= 1\n    \n        elif error and self._is_read_error(error):\n            # Read retry?\n            if read is False or method is None or not self._is_method_retryable(method):\n                raise reraise(type(error), error, _stacktrace)\n            elif read is not None:\n                read -= 1\n    \n        elif error:\n            # Other retry?\n            if other is not None:\n                other -= 1\n    \n        elif response and response.get_redirect_location():\n            # Redirect retry?\n            if redirect is not None:\n                redirect -= 1\n            cause = \"too many redirects\"\n            response_redirect_location = response.get_redirect_location()\n            if response_redirect_location:\n                redirect_location = response_redirect_location\n            status = response.status\n    \n        else:\n            # Incrementing because of a server error like a 500 in\n            # status_forcelist and the given method is in the allowed_methods\n            cause = ResponseError.GENERIC_ERROR\n            if response and response.status:\n                if status_count is not None:\n                    status_count -= 1\n                cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)\n                status = response.status\n    \n        history = self.history + (\n            RequestHistory(method, url, error, status, redirect_location),\n        )\n    \n        new_retry = self.new(\n            total=total,\n            connect=connect,\n            read=read,\n            redirect=redirect,\n            status=status_count,\n            other=other,\n            history=history,\n        )\n    \n        if new_retry.is_exhausted():\n            reason = error or ResponseError(cause)\n>           raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]\nE           urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/util/retry.py:519: MaxRetryError\n\nDuring handling of the above exception, another exception occurred:\n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n>               response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n\nllmisvc/test_llm_inference_service.py:1095: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\n\n    def post_with_retry(\n        url: str,\n        *,\n        headers: Dict = None,\n        json_data: Union[Dict, List] = None,\n        data: Union[str, bytes] = None,\n        stream: bool = False,\n        timeout: float = None,\n        total_retries: int = DEFAULT_RETRY_TOTAL,\n        backoff_factor: float = DEFAULT_RETRY_BACKOFF_FACTOR,\n        retry_status_codes=DEFAULT_RETRY_STATUS_CODES,\n    ) -> requests.Response:\n        \"\"\"\n        Send POST request with retries for transient HTTP and network failures.\n        \"\"\"\n        if json_data is not None and data is not None:\n            raise ValueError(\"Only one of json_data or data can be provided.\")\n    \n        with _retry_session(\n            [\"POST\"], total_retries, backoff_factor, retry_status_codes\n        ) as session:\n>           return session.post(\n                url,\n                json=json_data,\n                data=data,\n                headers=headers,\n                stream=stream,\n                timeout=timeout,\n            )\n\ncommon/http_retry.py:70: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f4f0dc37dd0>\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\ndata = None\njson = {'max_tokens': 20, 'model': 'facebook/opt-125m', 'prompt': 'KServe is a'}\nkwargs = {'headers': {'Content-Type': 'application/json'}, 'stream': False, 'timeout': 60}\n\n    def post(self, url, data=None, json=None, **kwargs):\n        r\"\"\"Sends a POST request. Returns :class:`Response` object.\n    \n        :param url: URL for the new :class:`Request` object.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the :class:`Request`.\n        :param \\*\\*kwargs: Optional arguments that ``request`` takes.\n        :rtype: requests.Response\n        \"\"\"\n    \n>       return self.request(\"POST\", url, data=data, json=json, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:637: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f4f0dc37dd0>, method = 'POST'\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions'\nparams = None, data = None, headers = {'Content-Type': 'application/json'}\ncookies = None, files = None, auth = None, timeout = 60, allow_redirects = True\nproxies = {}, hooks = None, stream = False, verify = None, cert = None\njson = {'max_tokens': 20, 'model': 'facebook/opt-125m', 'prompt': 'KServe is a'}\n\n    def request(\n        self,\n        method,\n        url,\n        params=None,\n        data=None,\n        headers=None,\n        cookies=None,\n        files=None,\n        auth=None,\n        timeout=None,\n        allow_redirects=True,\n        proxies=None,\n        hooks=None,\n        stream=None,\n        verify=None,\n        cert=None,\n        json=None,\n    ):\n        \"\"\"Constructs a :class:`Request <Request>`, prepares it and sends it.\n        Returns :class:`Response <Response>` object.\n    \n        :param method: method for the new :class:`Request` object.\n        :param url: URL for the new :class:`Request` object.\n        :param params: (optional) Dictionary or bytes to be sent in the query\n            string for the :class:`Request`.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the\n            :class:`Request`.\n        :param headers: (optional) Dictionary of HTTP Headers to send with the\n            :class:`Request`.\n        :param cookies: (optional) Dict or CookieJar object to send with the\n            :class:`Request`.\n        :param files: (optional) Dictionary of ``'filename': file-like-objects``\n            for multipart encoding upload.\n        :param auth: (optional) Auth tuple or callable to enable\n            Basic/Digest/Custom HTTP Auth.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple\n        :param allow_redirects: (optional) Set to True by default.\n        :type allow_redirects: bool\n        :param proxies: (optional) Dictionary mapping protocol or protocol and\n            hostname to the URL of the proxy.\n        :param hooks: (optional) Dictionary mapping hook name to one event or\n            list of events, event must be callable.\n        :param stream: (optional) whether to immediately download the response\n            content. Defaults to ``False``.\n        :param verify: (optional) Either a boolean, in which case it controls whether we verify\n            the server's TLS certificate, or a string, in which case it must be a path\n            to a CA bundle to use. Defaults to ``True``. When set to\n            ``False``, requests will accept any TLS certificate presented by\n            the server, and will ignore hostname mismatches and/or expired\n            certificates, which will make your application vulnerable to\n            man-in-the-middle (MitM) attacks. Setting verify to ``False``\n            may be useful during local development or testing.\n        :param cert: (optional) if String, path to ssl client cert file (.pem).\n            If Tuple, ('cert', 'key') pair.\n        :rtype: requests.Response\n        \"\"\"\n        # Create the Request.\n        req = Request(\n            method=method.upper(),\n            url=url,\n            headers=headers,\n            files=files,\n            data=data or {},\n            json=json,\n            params=params or {},\n            auth=auth,\n            cookies=cookies,\n            hooks=hooks,\n        )\n        prep = self.prepare_request(req)\n    \n        proxies = proxies or {}\n    \n        settings = self.merge_environment_settings(\n            prep.url, proxies, stream, verify, cert\n        )\n    \n        # Send the request.\n        send_kwargs = {\n            \"timeout\": timeout,\n            \"allow_redirects\": allow_redirects,\n        }\n        send_kwargs.update(settings)\n>       resp = self.send(prep, **send_kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:589: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f4f0dc37dd0>\nrequest = <PreparedRequest [POST]>\nkwargs = {'cert': None, 'proxies': OrderedDict(), 'stream': False, 'timeout': 60, ...}\nallow_redirects = True, stream = False, hooks = {'response': []}\nadapter = <requests.adapters.HTTPAdapter object at 0x7f4f0db51a10>\nstart = 1783434821.7591457\n\n    def send(self, request, **kwargs):\n        \"\"\"Send a given PreparedRequest.\n    \n        :rtype: requests.Response\n        \"\"\"\n        # Set defaults that the hooks can utilize to ensure they always have\n        # the correct parameters to reproduce the previous request.\n        kwargs.setdefault(\"stream\", self.stream)\n        kwargs.setdefault(\"verify\", self.verify)\n        kwargs.setdefault(\"cert\", self.cert)\n        if \"proxies\" not in kwargs:\n            kwargs[\"proxies\"] = resolve_proxies(request, self.proxies, self.trust_env)\n    \n        # It's possible that users might accidentally send a Request object.\n        # Guard against that specific failure case.\n        if isinstance(request, Request):\n            raise ValueError(\"You can only send PreparedRequests.\")\n    \n        # Set up variables needed for resolve_redirects and dispatching of hooks\n        allow_redirects = kwargs.pop(\"allow_redirects\", True)\n        stream = kwargs.get(\"stream\")\n        hooks = request.hooks\n    \n        # Get the appropriate adapter to use\n        adapter = self.get_adapter(url=request.url)\n    \n        # Start time (approximately) of the request\n        start = preferred_clock()\n    \n        # Send the request\n>       r = adapter.send(request, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:703: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.adapters.HTTPAdapter object at 0x7f4f0db51a10>\nrequest = <PreparedRequest [POST]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n            resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n    \n        except (ProtocolError, OSError) as err:\n            raise ConnectionError(err, request=request)\n    \n        except MaxRetryError as e:\n            if isinstance(e.reason, ConnectTimeoutError):\n                # TODO: Remove this in 3.0.0: see #2811\n                if not isinstance(e.reason, NewConnectionError):\n                    raise ConnectTimeout(e, request=request)\n    \n            if isinstance(e.reason, ResponseError):\n                raise RetryError(e, request=request)\n    \n            if isinstance(e.reason, _ProxyError):\n                raise ProxyError(e, request=request)\n    \n            if isinstance(e.reason, _SSLError):\n                # This branch is for urllib3 v1.22 and later.\n                raise SSLError(e, request=request)\n    \n>           raise ConnectionError(e, request=request)\nE           requests.exceptions.ConnectionError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:700: ConnectionError\n\nThe above exception was the direct cause of the following exception:\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-single-cpu', 'model-fb-opt-125m'], prompt='KServe is a', service_name=...              {'name': 'model-fb-opt-125m-llmisvc-model-2a331009'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.llminferenceservice\n    @pytest.mark.asyncio(loop_scope=\"session\")\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-gateway-ref\",\n                        \"router-with-managed-route\",\n                        \"model-fb-opt-125m\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=create_response_assertion(with_field=\"choices\"),\n                    expected_gateway=ROUTER_GATEWAYS[0],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[0]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-custom-route-timeout\",\n                        \"scheduler-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"custom-route-timeout-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-refs\",\n                        \"scheduler-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"router-with-refs-test\",\n                    expected_gateway=ROUTER_GATEWAYS[0],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[0]],\n                            routes=[ROUTER_ROUTES[0], ROUTER_ROUTES[1]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\"router-managed\", \"workload-pd-cpu\", \"model-fb-opt-125m\"],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-custom-route-timeout-pd\",\n                        \"scheduler-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    service_name=\"custom-route-timeout-pd-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-refs-pd\",\n                        \"scheduler-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    service_name=\"router-with-refs-pd-test\",\n                    response_assertion=assert_200_with_choices,\n                    expected_gateway=ROUTER_GATEWAYS[1],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[1]],\n                            routes=[ROUTER_ROUTES[2], ROUTER_ROUTES[3]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-dp-ep-gpu\",\n                        \"workload-dp-ep-prefill-gpu\",\n                        \"model-deepseek-v2-lite\",\n                    ],\n                    prompt=\"Delve into the multifaceted implications of a fully disaggregated cloud architecture, specifically \"\n                    \"where the compute plane (P) and the data plane (D) are independently deployed and managed for a \"\n                    \"geographically distributed, high-throughput, low-latency microservices ecosystem. Beyond the \"\n                    \"fundamental challenges of network latency and data consistency, elaborate on the advanced \"\n                    \"considerations and trade-offs inherent in such a setup: 1. Network Architecture and Protocols: \"\n                    \"How would the network fabric and underlying protocols (e.g., RDMA, custom transport layers) need to \"\n                    \"evolve to support optimal performance and minimize inter-plane communication overhead, especially for \"\n                    \"synchronous operations? Discuss the role of network programmability (e.g., SDN, P4) in dynamically \"\n                    \"optimizing routing and traffic flow between P and D. 2. Advanced Data Consistency and Durability: \"\n                    \"Explore sophisticated data consistency models (e.g., causal consistency, strong eventual consistency) \"\n                    \"and their applicability in balancing performance and data integrity across a globally distributed data plane. \"\n                    \"Detail strategies for ensuring data durability and fault tolerance, including multi-region replication, \"\n                    \"intelligent partitioning, and recovery mechanisms in the event of partial or full plane failures. \"\n                    \"3. Dynamic Resource Orchestration and Cost Optimization: Analyze how an orchestration layer would intelligently \"\n                    \"manage the independent scaling of compute (P) and data (D) resources, considering fluctuating workloads, \"\n                    \"cost efficiency, and performance targets (e.g., using predictive analytics for resource provisioning). \"\n                    \"Discuss mechanisms for dynamically reallocating compute nodes to different data partitions based on \"\n                    \"workload patterns and data locality, potentially involving live migration strategies. \"\n                    \"4. Security and Compliance in a Distributed Landscape: Address the enhanced security perimeter \"\n                    \"challenges, including securing communication channels between P and D (encryption in transit, mutual TLS), \"\n                    \"fine-grained access control to data at rest and in motion, and identity management across disaggregated \"\n                    \"components. Discuss how such an architecture impacts compliance with regulatory frameworks (e.g., GDPR, HIPAA) \"\n                    \"concerning data sovereignty, privacy, and auditability. 5. Operational Complexity and Observability: \"\n                    \"Examine the increased complexity in monitoring, logging, and tracing across highly decoupled compute and \"\n                    \"data planes. What specialized tooling and practices (e.g., distributed tracing with OpenTelemetry, advanced AIOps) \"\n                    \"would be essential? How would incident response and troubleshooting differ in this disaggregated environment \"\n                    \"compared to traditional integrated systems? Consider the challenges of pinpointing root causes across \"\n                    \"independent failures. 6. Real-world Applicability and Future Trends: Identify specific industries \"\n                    \"or use cases (e.g., high-frequency trading, IoT edge processing, large language model inference) \"\n                    \"where the benefits of P/D disaggregation would strongly outweigh its complexities. \"\n                    \"Conclude by speculating on emerging technologies or paradigms (e.g., serverless compute functions \"\n                    \"directly interacting with object storage, in-memory disaggregation) that could further drive or \"\n                    \"transform P/D disaggregation in cloud computing.\",\n                    max_tokens=2000,\n                ),\n                marks=[\n                    pytest.mark.cluster_gpu,\n                    pytest.mark.cluster_nvidia,\n                    pytest.mark.cluster_nvidia_roce,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-no-scheduler\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"What is KServe?\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.no_scheduler,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-simulated-dp-ep-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"This test simulates DP+EP that can run on CPU, the idea is to test the LWS-based deployment, \"\n                    \"but without the resources requirements for DP+EP (GPUs and ROCe/IB).\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_multi_node],\n            ),\n            # Scheduler config tests\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-inline-config\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-inline-config-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            # Chat completions endpoint coverage\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                        \"model-qwen2.5-0.5b\",\n                    ],\n                    model_name=\"Qwen/Qwen2.5-0.5B-Instruct\",\n                    endpoint=\"/v1/chat/completions\",\n                    prompt=\"What is KServe?\",\n                    payload_formatter=chat_completions_payload,\n                    response_assertion=create_response_assertion(with_field=\"choices\"),\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-configmap-ref\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-configmap-ref-test\",\n                    before_test=[create_scheduler_configmap],\n                    after_test=[delete_scheduler_configmap],\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-replicas\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-ha-replicas-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-custom-template\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-custom-template-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            # Scheduler v0.6 \u2192 v0.7 migration tests.\n            # Deploy v0.6-style configs and verify the controller migrates them\n            # so the v0.7 scheduler boots successfully.\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-v06-pd-config-migration\",\n                        \"workload-llmd-simulator-pd\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-v06-pd-migration-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-v06-nonzero-threshold-migration\",\n                        \"workload-llmd-simulator-pd\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-v06-threshold-migration-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Precise prefix KV cache routing test\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-precise-prefix-cache-inline-config\",\n                        \"workload-llmd-simulator-kvcache\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"precise-prefix-cache-test\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Models endpoint coverage\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/models\",\n                    response_assertion=create_response_assertion(with_field=\"data\"),\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/completions\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\"facebook/opt-125m\"),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                    peers=[\n                        TestCase(\n                            base_refs=[\n                                \"router-managed\",\n                                \"workload-llmd-simulator\",\n                                \"model-qwen2.5-0.5b\",\n                            ],\n                            endpoint=\"/v1/completions\",\n                            prompt=\"KServe is a\",\n                            payload_formatter=completions_payload,\n                            response_assertion=assert_model_field_matches(\n                                \"Qwen/Qwen2.5-0.5B-Instruct\"\n                            ),\n                            url_getter=get_model_routing_url,\n                            extra_headers={\n                                MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/Qwen/Qwen2.5-0.5B-Instruct\",\n                            },\n                        ),\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.model_routing,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/chat/completions\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/chat/completions\",\n                    prompt=\"What is KServe?\",\n                    payload_formatter=chat_completions_payload,\n                    response_assertion=assert_model_field_matches(\"facebook/opt-125m\"),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                    peers=[\n                        TestCase(\n                            base_refs=[\n                                \"router-managed\",\n                                \"workload-llmd-simulator\",\n                                \"model-qwen2.5-0.5b\",\n                            ],\n                            endpoint=\"/v1/chat/completions\",\n                            prompt=\"What is KServe?\",\n                            payload_formatter=chat_completions_payload,\n                            response_assertion=assert_model_field_matches(\n                                \"Qwen/Qwen2.5-0.5B-Instruct\"\n                            ),\n                            url_getter=get_model_routing_url,\n                            extra_headers={\n                                MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/Qwen/Qwen2.5-0.5B-Instruct\",\n                            },\n                        ),\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.model_routing,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 LoRA adapter\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m-with-lora-hf\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    model_name=f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\"\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    },\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.model_routing,\n                    pytest.mark.lora,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/models (base + LoRA)\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m-with-lora-hf\",\n                    ],\n                    endpoint=\"/v1/models\",\n                    response_assertion=assert_models_contains(\n                        \"facebook/opt-125m\",\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                        \"lora-adapter-1\",\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.model_routing,\n                    pytest.mark.lora,\n                ],\n            ),\n            # PVC storage tests -- validate direct PVC volume mount with real vLLM serving\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    response_assertion=assert_200_with_choices,\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    response_assertion=assert_200_with_choices,\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-simulated-dp-ep-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_multi_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_inference_service(test_case: TestCase):  # noqa: F811\n        inject_k8s_proxy()\n    \n        kserve_client = KServeClient(\n            config_file=os.environ.get(\"KUBECONFIG\", \"~/.kube/config\"),\n            client_configuration=client.Configuration(),\n        )\n    \n        service_name = test_case.llm_service.metadata.name\n        if not test_case.llm_service.metadata.annotations:\n            test_case.llm_service.metadata.annotations = {}\n    \n        test_case.llm_service.metadata.annotations[\n            \"security.opendatahub.io/enable-auth\"\n        ] = \"false\"\n        prefix = test_case.log_prefix\n    \n        test_failed = False\n        try:\n            print(f\"{prefix} Creating LLMInferenceService {service_name}\")\n            create_llmisvc(kserve_client, test_case.llm_service)\n            print(f\"{prefix} Waiting for LLMInferenceService {service_name} to be ready\")\n            wait_for_llm_isvc_ready(\n                kserve_client, test_case.llm_service, test_case.wait_timeout\n            )\n            print(f\"{prefix} Waiting for model response from {service_name}\")\n>           wait_for_model_response(\n                kserve_client,\n                test_case,\n                test_case.wait_timeout,\n                extra_headers=test_case.extra_headers,\n            )\n\nllmisvc/test_llm_inference_service.py:816: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f4f0dc81e10>, TestCase(base_refs=['router-managed', 'workload-sin...        {'name': 'model-fb-opt-125m-llmisvc-model-2a331009'}]},\n 'status': None}, model_name='facebook/opt-125m'), 900)\nkwargs = {'extra_headers': None}, func_name = 'wait_for_model_response'\ntimestamp_start = '2026-07-07T14:33:41.745372', start_time = 1783434821.7457728\nduration = 904.5519132614136, timestamp_end = '2026-07-07T14:48:46.297689'\n\n    @functools.wraps(func)\n    def wrapper(*args, **kwargs):\n        func_name = func.__name__\n    \n        timestamp_start = datetime.now().isoformat()\n        logger.info(\n            f\"[{func_name}] [{timestamp_start}] start - args={args}, kwargs={kwargs}\"\n        )\n        start_time = time.time()\n    \n        try:\n>           result = func(*args, **kwargs)\n\nllmisvc/logging.py:40: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f4f0dc81e10>\ntest_case = TestCase(base_refs=['router-managed', 'workload-single-cpu', 'model-fb-opt-125m'], prompt='KServe is a', service_name=...              {'name': 'model-fb-opt-125m-llmisvc-model-2a331009'}]},\n 'status': None}, model_name='facebook/opt-125m')\ntimeout_seconds = 900, extra_headers = None\n\n    @log_execution\n    def wait_for_model_response(\n        kserve_client: KServeClient,\n        test_case: TestCase,  # noqa: F811\n        timeout_seconds: int = 900,\n        extra_headers: Optional[Dict[str, str]] = None,\n    ) -> str:\n        def get_successful_response():\n            try:\n                if test_case.url_getter:\n                    service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n                else:\n                    service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n            except Exception as e:\n                raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n            model_url = service_url + test_case.endpoint\n    \n            headers = {\"Content-Type\": \"application/json\"}\n            if extra_headers:\n                headers.update(extra_headers)\n    \n            if test_case.payload_formatter is not None:\n                test_payload = test_case.payload_formatter(test_case)\n            elif test_case.prompt is not None:\n                test_payload = {\n                    \"model\": test_case.model_name\n                    if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                    else extra_headers[MODEL_ROUTING_HEADER],\n                    \"prompt\": test_case.prompt,\n                    \"max_tokens\": test_case.max_tokens,\n                }\n            else:\n                test_payload = None\n    \n            logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n            try:\n                if test_payload is not None:\n                    response = post_with_retry(\n                        model_url,\n                        headers=headers,\n                        json_data=test_payload,\n                        timeout=test_case.response_timeout,\n                    )\n                else:\n                    response = get_with_retry(\n                        model_url,\n                        headers=headers,\n                        timeout=test_case.response_timeout,\n                    )\n            except Exception as e:\n                logger.error(f\"\u274c Failed to call model: {e}\")\n                raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\n    \n            logger.info(f\"Model response is {response.status_code}: {response.text[:500]}\")\n    \n            if 200 <= response.status_code < 300:\n                return response\n            raise AssertionError(\n                f\"Service returned {response.status_code}: {response.text}\"\n            )\n    \n>       response = wait_for(get_successful_response, timeout=timeout_seconds, interval=5.0)\n\nllmisvc/test_llm_inference_service.py:1119: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_model_response.<locals>.get_successful_response at 0x7f4f0dde3e20>\ntimeout = 900, interval = 5.0\n\n    def wait_for(\n        assertion_fn: Callable[[], Any], timeout: float = 5.0, interval: float = 0.1\n    ) -> Any:\n        \"\"\"Wait for the assertion to succeed within timeout.\"\"\"\n        deadline = time.time() + timeout\n        last_msg = None\n        while True:\n            try:\n>               return assertion_fn()\n\nllmisvc/test_llm_inference_service.py:1215: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n                response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n            else:\n                response = get_with_retry(\n                    model_url,\n                    headers=headers,\n                    timeout=test_case.response_timeout,\n                )\n        except Exception as e:\n            logger.error(f\"\u274c Failed to call model: {e}\")\n>           raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\nE           AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/llmisvc-model-fb-opt-125m-route-87882a8e/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\nllmisvc/test_llm_inference_service.py:1109: AssertionError"}, "teardown": {"duration": 0.0019799100009549875, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf1]", "lineno": 244, "outcome": "failed", "keywords": ["test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf1]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "model_routing", "lora", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf1", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.12179520800054888, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 990.8313340629975, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /v1/models (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))"}, "traceback": [{"path": "llmisvc/test_llm_inference_service.py", "lineno": 816, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1119, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1215, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError"}], "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17502dd0>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17502dd0>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n>           response = conn.getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:534: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17502dd0>\n\n    def getresponse(  # type: ignore[override]\n        self,\n    ) -> HTTPResponse:\n        \"\"\"\n        Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an instance of HTTPResponse or of whatever object is returned by the response_class variable.\n    \n        If a request has not been sent or if a previous response has not be handled, ResponseNotReady is raised. If the HTTP response indicates that the connection should be closed, then it will be closed before the response is returned. When the connection is closed, the underlying socket is closed.\n        \"\"\"\n        # Raise the same error as http.client.HTTPConnection\n        if self._response_options is None:\n            raise ResponseNotReady()\n    \n        # Reset this attribute for being used again.\n        resp_options = self._response_options\n        self._response_options = None\n    \n        # Since the connection's timeout value may have been updated\n        # we need to set the timeout on the socket.\n        self.sock.settimeout(self.timeout)\n    \n        # This is needed here to avoid circular import errors\n        from .response import HTTPResponse\n    \n        # Save a reference to the shutdown function before ownership is passed\n        # to httplib_response\n        # TODO should we implement it everywhere?\n        _shutdown = getattr(self.sock, \"shutdown\", None)\n    \n        # Get the response from http.client.HTTPConnection\n>       httplib_response = super().getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connection.py:571: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17502dd0>\n\n    def getresponse(self):\n        \"\"\"Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an\n        instance of HTTPResponse or of whatever object is returned by\n        the response_class variable.\n    \n        If a request has not been sent or if a previous response has\n        not be handled, ResponseNotReady is raised.  If the HTTP\n        response indicates that the connection should be closed, then\n        it will be closed before the response is returned.  When the\n        connection is closed, the underlying socket is closed.\n        \"\"\"\n    \n        # if a prior response has been completed, then forget about it.\n        if self.__response and self.__response.isclosed():\n            self.__response = None\n    \n        # if a prior response exists, then it must be completed (otherwise, we\n        # cannot read this response's header to determine the connection-close\n        # behavior)\n        #\n        # note: if a prior response existed, but was connection-close, then the\n        # socket and response were made independent of this HTTPConnection\n        # object since a new request requires that we open a whole new\n        # connection\n        #\n        # this means the prior response had one of two states:\n        #   1) will_close: this connection was reset and the prior socket and\n        #                  response operate independently\n        #   2) persistent: the response was retained and we await its\n        #                  isclosed() status to become true.\n        #\n        if self.__state != _CS_REQ_SENT or self.__response:\n            raise ResponseNotReady(self.__state)\n    \n        if self.debuglevel > 0:\n            response = self.response_class(self.sock, self.debuglevel,\n                                           method=self._method)\n        else:\n            response = self.response_class(self.sock, method=self._method)\n    \n        try:\n            try:\n>               response.begin()\n\n/usr/lib64/python3.11/http/client.py:1395: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f1d17690430>\n\n    def begin(self):\n        if self.headers is not None:\n            # we've already started reading the response\n            return\n    \n        # read until we get a non-100 response\n        while True:\n>           version, status, reason = self._read_status()\n\n/usr/lib64/python3.11/http/client.py:325: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f1d17690430>\n\n    def _read_status(self):\n>       line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n\n/usr/lib64/python3.11/http/client.py:286: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <socket.SocketIO object at 0x7f1d17690b80>\nb = <memory at 0x7f1d17bbfac0>\n\n    def readinto(self, b):\n        \"\"\"Read up to len(b) bytes into the writable buffer *b* and return\n        the number of bytes read.  If the socket is non-blocking and no bytes\n        are available, None is returned.\n    \n        If *b* is non-empty, a 0 return value indicates that the connection\n        was shutdown at the other end.\n        \"\"\"\n        self._checkClosed()\n        self._checkReadable()\n        if self._timeout_occurred:\n            raise OSError(\"cannot read from timed out object\")\n        while True:\n            try:\n>               return self._sock.recv_into(b)\nE               TimeoutError: timed out\n\n/usr/lib64/python3.11/socket.py:718: TimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n>           response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:787: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17502dd0>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d17502dd0>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n            response = conn.getresponse()\n        except (BaseSSLError, OSError) as e:\n>           self._raise_timeout(err=e, url=url, timeout_value=read_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:536: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nerr = TimeoutError('timed out'), url = '/v1/models', timeout_value = 60\n\n    def _raise_timeout(\n        self,\n        err: BaseSSLError | OSError | SocketTimeout,\n        url: str,\n        timeout_value: _TYPE_TIMEOUT | None,\n    ) -> None:\n        \"\"\"Is the error actually a timeout? Will raise a ReadTimeout or pass\"\"\"\n    \n        if isinstance(err, SocketTimeout):\n>           raise ReadTimeoutError(\n                self, url, f\"Read timed out. (read timeout={timeout_value})\"\n            ) from err\nE           urllib3.exceptions.ReadTimeoutError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:367: ReadTimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <requests.adapters.HTTPAdapter object at 0x7f1d174d3b50>\nrequest = <PreparedRequest [GET]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n>           resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:667: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=7, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=6, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = RemoteDisconnected('Remote end closed connection without response')\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=5, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=4, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=3, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=2, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=1, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\nmethod = 'GET', url = '/v1/models', body = None\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/v1/models', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n>           retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:841: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nmethod = 'GET', url = '/v1/models', response = None\nerror = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\n_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d174d0610>\n_stacktrace = <traceback object at 0x7f1d17502d80>\n\n    def increment(\n        self,\n        method: str | None = None,\n        url: str | None = None,\n        response: BaseHTTPResponse | None = None,\n        error: Exception | None = None,\n        _pool: ConnectionPool | None = None,\n        _stacktrace: TracebackType | None = None,\n    ) -> Self:\n        \"\"\"Return a new Retry object with incremented retry counters.\n    \n        :param response: A response object, or None, if the server did not\n            return a response.\n        :type response: :class:`~urllib3.response.BaseHTTPResponse`\n        :param Exception error: An error encountered during the request, or\n            None if the response was received successfully.\n    \n        :return: A new ``Retry`` object.\n        \"\"\"\n        if self.total is False and error:\n            # Disabled, indicate to re-raise the error.\n            raise reraise(type(error), error, _stacktrace)\n    \n        total = self.total\n        if total is not None:\n            total -= 1\n    \n        connect = self.connect\n        read = self.read\n        redirect = self.redirect\n        status_count = self.status\n        other = self.other\n        cause = \"unknown\"\n        status = None\n        redirect_location = None\n    \n        if error and self._is_connection_error(error):\n            # Connect retry?\n            if connect is False:\n                raise reraise(type(error), error, _stacktrace)\n            elif connect is not None:\n                connect -= 1\n    \n        elif error and self._is_read_error(error):\n            # Read retry?\n            if read is False or method is None or not self._is_method_retryable(method):\n                raise reraise(type(error), error, _stacktrace)\n            elif read is not None:\n                read -= 1\n    \n        elif error:\n            # Other retry?\n            if other is not None:\n                other -= 1\n    \n        elif response and response.get_redirect_location():\n            # Redirect retry?\n            if redirect is not None:\n                redirect -= 1\n            cause = \"too many redirects\"\n            response_redirect_location = response.get_redirect_location()\n            if response_redirect_location:\n                redirect_location = response_redirect_location\n            status = response.status\n    \n        else:\n            # Incrementing because of a server error like a 500 in\n            # status_forcelist and the given method is in the allowed_methods\n            cause = ResponseError.GENERIC_ERROR\n            if response and response.status:\n                if status_count is not None:\n                    status_count -= 1\n                cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)\n                status = response.status\n    \n        history = self.history + (\n            RequestHistory(method, url, error, status, redirect_location),\n        )\n    \n        new_retry = self.new(\n            total=total,\n            connect=connect,\n            read=read,\n            redirect=redirect,\n            status=status_count,\n            other=other,\n            history=history,\n        )\n    \n        if new_retry.is_exhausted():\n            reason = error or ResponseError(cause)\n>           raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]\nE           urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /v1/models (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/util/retry.py:519: MaxRetryError\n\nDuring handling of the above exception, another exception occurred:\n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n                response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n            else:\n>               response = get_with_retry(\n                    model_url,\n                    headers=headers,\n                    timeout=test_case.response_timeout,\n                )\n\nllmisvc/test_llm_inference_service.py:1102: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/v1/models'\n\n    def get_with_retry(\n        url: str,\n        *,\n        headers: Dict = None,\n        timeout: float = None,\n        total_retries: int = DEFAULT_RETRY_TOTAL,\n        backoff_factor: float = DEFAULT_RETRY_BACKOFF_FACTOR,\n        retry_status_codes=DEFAULT_RETRY_STATUS_CODES,\n    ) -> requests.Response:\n        \"\"\"\n        Send GET request with retries for transient HTTP and network failures.\n        \"\"\"\n        with _retry_session(\n            [\"GET\"], total_retries, backoff_factor, retry_status_codes\n        ) as session:\n>           return session.get(url, headers=headers, timeout=timeout)\n\ncommon/http_retry.py:46: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d174f3190>\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/v1/models'\nkwargs = {'allow_redirects': True, 'headers': {'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}, 'timeout': 60}\n\n    def get(self, url, **kwargs):\n        r\"\"\"Sends a GET request. Returns :class:`Response` object.\n    \n        :param url: URL for the new :class:`Request` object.\n        :param \\*\\*kwargs: Optional arguments that ``request`` takes.\n        :rtype: requests.Response\n        \"\"\"\n    \n        kwargs.setdefault(\"allow_redirects\", True)\n>       return self.request(\"GET\", url, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:602: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d174f3190>, method = 'GET'\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/v1/models'\nparams = None, data = None\nheaders = {'Content-Type': 'application/json', 'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\ncookies = None, files = None, auth = None, timeout = 60, allow_redirects = True\nproxies = {}, hooks = None, stream = None, verify = None, cert = None\njson = None\n\n    def request(\n        self,\n        method,\n        url,\n        params=None,\n        data=None,\n        headers=None,\n        cookies=None,\n        files=None,\n        auth=None,\n        timeout=None,\n        allow_redirects=True,\n        proxies=None,\n        hooks=None,\n        stream=None,\n        verify=None,\n        cert=None,\n        json=None,\n    ):\n        \"\"\"Constructs a :class:`Request <Request>`, prepares it and sends it.\n        Returns :class:`Response <Response>` object.\n    \n        :param method: method for the new :class:`Request` object.\n        :param url: URL for the new :class:`Request` object.\n        :param params: (optional) Dictionary or bytes to be sent in the query\n            string for the :class:`Request`.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the\n            :class:`Request`.\n        :param headers: (optional) Dictionary of HTTP Headers to send with the\n            :class:`Request`.\n        :param cookies: (optional) Dict or CookieJar object to send with the\n            :class:`Request`.\n        :param files: (optional) Dictionary of ``'filename': file-like-objects``\n            for multipart encoding upload.\n        :param auth: (optional) Auth tuple or callable to enable\n            Basic/Digest/Custom HTTP Auth.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple\n        :param allow_redirects: (optional) Set to True by default.\n        :type allow_redirects: bool\n        :param proxies: (optional) Dictionary mapping protocol or protocol and\n            hostname to the URL of the proxy.\n        :param hooks: (optional) Dictionary mapping hook name to one event or\n            list of events, event must be callable.\n        :param stream: (optional) whether to immediately download the response\n            content. Defaults to ``False``.\n        :param verify: (optional) Either a boolean, in which case it controls whether we verify\n            the server's TLS certificate, or a string, in which case it must be a path\n            to a CA bundle to use. Defaults to ``True``. When set to\n            ``False``, requests will accept any TLS certificate presented by\n            the server, and will ignore hostname mismatches and/or expired\n            certificates, which will make your application vulnerable to\n            man-in-the-middle (MitM) attacks. Setting verify to ``False``\n            may be useful during local development or testing.\n        :param cert: (optional) if String, path to ssl client cert file (.pem).\n            If Tuple, ('cert', 'key') pair.\n        :rtype: requests.Response\n        \"\"\"\n        # Create the Request.\n        req = Request(\n            method=method.upper(),\n            url=url,\n            headers=headers,\n            files=files,\n            data=data or {},\n            json=json,\n            params=params or {},\n            auth=auth,\n            cookies=cookies,\n            hooks=hooks,\n        )\n        prep = self.prepare_request(req)\n    \n        proxies = proxies or {}\n    \n        settings = self.merge_environment_settings(\n            prep.url, proxies, stream, verify, cert\n        )\n    \n        # Send the request.\n        send_kwargs = {\n            \"timeout\": timeout,\n            \"allow_redirects\": allow_redirects,\n        }\n        send_kwargs.update(settings)\n>       resp = self.send(prep, **send_kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:589: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d174f3190>\nrequest = <PreparedRequest [GET]>\nkwargs = {'cert': None, 'proxies': OrderedDict(), 'stream': False, 'timeout': 60, ...}\nallow_redirects = True, stream = False, hooks = {'response': []}\nadapter = <requests.adapters.HTTPAdapter object at 0x7f1d174d3b50>\nstart = 1783435637.8514826\n\n    def send(self, request, **kwargs):\n        \"\"\"Send a given PreparedRequest.\n    \n        :rtype: requests.Response\n        \"\"\"\n        # Set defaults that the hooks can utilize to ensure they always have\n        # the correct parameters to reproduce the previous request.\n        kwargs.setdefault(\"stream\", self.stream)\n        kwargs.setdefault(\"verify\", self.verify)\n        kwargs.setdefault(\"cert\", self.cert)\n        if \"proxies\" not in kwargs:\n            kwargs[\"proxies\"] = resolve_proxies(request, self.proxies, self.trust_env)\n    \n        # It's possible that users might accidentally send a Request object.\n        # Guard against that specific failure case.\n        if isinstance(request, Request):\n            raise ValueError(\"You can only send PreparedRequests.\")\n    \n        # Set up variables needed for resolve_redirects and dispatching of hooks\n        allow_redirects = kwargs.pop(\"allow_redirects\", True)\n        stream = kwargs.get(\"stream\")\n        hooks = request.hooks\n    \n        # Get the appropriate adapter to use\n        adapter = self.get_adapter(url=request.url)\n    \n        # Start time (approximately) of the request\n        start = preferred_clock()\n    \n        # Send the request\n>       r = adapter.send(request, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:703: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.adapters.HTTPAdapter object at 0x7f1d174d3b50>\nrequest = <PreparedRequest [GET]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n            resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n    \n        except (ProtocolError, OSError) as err:\n            raise ConnectionError(err, request=request)\n    \n        except MaxRetryError as e:\n            if isinstance(e.reason, ConnectTimeoutError):\n                # TODO: Remove this in 3.0.0: see #2811\n                if not isinstance(e.reason, NewConnectionError):\n                    raise ConnectTimeout(e, request=request)\n    \n            if isinstance(e.reason, ResponseError):\n                raise RetryError(e, request=request)\n    \n            if isinstance(e.reason, _ProxyError):\n                raise ProxyError(e, request=request)\n    \n            if isinstance(e.reason, _SSLError):\n                # This branch is for urllib3 v1.22 and later.\n                raise SSLError(e, request=request)\n    \n>           raise ConnectionError(e, request=request)\nE           requests.exceptions.ConnectionError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /v1/models (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:700: ConnectionError\n\nThe above exception was the direct cause of the following exception:\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-single-cpu', 'model-fb-opt-125m-with-lora-hf'], prompt=None, service_n...               {'name': 'model-fb-opt-125m-with-lora-hf-c0d503b0'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.llminferenceservice\n    @pytest.mark.asyncio(loop_scope=\"session\")\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-gateway-ref\",\n                        \"router-with-managed-route\",\n                        \"model-fb-opt-125m\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=create_response_assertion(with_field=\"choices\"),\n                    expected_gateway=ROUTER_GATEWAYS[0],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[0]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-custom-route-timeout\",\n                        \"scheduler-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"custom-route-timeout-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-refs\",\n                        \"scheduler-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"router-with-refs-test\",\n                    expected_gateway=ROUTER_GATEWAYS[0],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[0]],\n                            routes=[ROUTER_ROUTES[0], ROUTER_ROUTES[1]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\"router-managed\", \"workload-pd-cpu\", \"model-fb-opt-125m\"],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-custom-route-timeout-pd\",\n                        \"scheduler-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    service_name=\"custom-route-timeout-pd-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-refs-pd\",\n                        \"scheduler-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    service_name=\"router-with-refs-pd-test\",\n                    response_assertion=assert_200_with_choices,\n                    expected_gateway=ROUTER_GATEWAYS[1],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[1]],\n                            routes=[ROUTER_ROUTES[2], ROUTER_ROUTES[3]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-dp-ep-gpu\",\n                        \"workload-dp-ep-prefill-gpu\",\n                        \"model-deepseek-v2-lite\",\n                    ],\n                    prompt=\"Delve into the multifaceted implications of a fully disaggregated cloud architecture, specifically \"\n                    \"where the compute plane (P) and the data plane (D) are independently deployed and managed for a \"\n                    \"geographically distributed, high-throughput, low-latency microservices ecosystem. Beyond the \"\n                    \"fundamental challenges of network latency and data consistency, elaborate on the advanced \"\n                    \"considerations and trade-offs inherent in such a setup: 1. Network Architecture and Protocols: \"\n                    \"How would the network fabric and underlying protocols (e.g., RDMA, custom transport layers) need to \"\n                    \"evolve to support optimal performance and minimize inter-plane communication overhead, especially for \"\n                    \"synchronous operations? Discuss the role of network programmability (e.g., SDN, P4) in dynamically \"\n                    \"optimizing routing and traffic flow between P and D. 2. Advanced Data Consistency and Durability: \"\n                    \"Explore sophisticated data consistency models (e.g., causal consistency, strong eventual consistency) \"\n                    \"and their applicability in balancing performance and data integrity across a globally distributed data plane. \"\n                    \"Detail strategies for ensuring data durability and fault tolerance, including multi-region replication, \"\n                    \"intelligent partitioning, and recovery mechanisms in the event of partial or full plane failures. \"\n                    \"3. Dynamic Resource Orchestration and Cost Optimization: Analyze how an orchestration layer would intelligently \"\n                    \"manage the independent scaling of compute (P) and data (D) resources, considering fluctuating workloads, \"\n                    \"cost efficiency, and performance targets (e.g., using predictive analytics for resource provisioning). \"\n                    \"Discuss mechanisms for dynamically reallocating compute nodes to different data partitions based on \"\n                    \"workload patterns and data locality, potentially involving live migration strategies. \"\n                    \"4. Security and Compliance in a Distributed Landscape: Address the enhanced security perimeter \"\n                    \"challenges, including securing communication channels between P and D (encryption in transit, mutual TLS), \"\n                    \"fine-grained access control to data at rest and in motion, and identity management across disaggregated \"\n                    \"components. Discuss how such an architecture impacts compliance with regulatory frameworks (e.g., GDPR, HIPAA) \"\n                    \"concerning data sovereignty, privacy, and auditability. 5. Operational Complexity and Observability: \"\n                    \"Examine the increased complexity in monitoring, logging, and tracing across highly decoupled compute and \"\n                    \"data planes. What specialized tooling and practices (e.g., distributed tracing with OpenTelemetry, advanced AIOps) \"\n                    \"would be essential? How would incident response and troubleshooting differ in this disaggregated environment \"\n                    \"compared to traditional integrated systems? Consider the challenges of pinpointing root causes across \"\n                    \"independent failures. 6. Real-world Applicability and Future Trends: Identify specific industries \"\n                    \"or use cases (e.g., high-frequency trading, IoT edge processing, large language model inference) \"\n                    \"where the benefits of P/D disaggregation would strongly outweigh its complexities. \"\n                    \"Conclude by speculating on emerging technologies or paradigms (e.g., serverless compute functions \"\n                    \"directly interacting with object storage, in-memory disaggregation) that could further drive or \"\n                    \"transform P/D disaggregation in cloud computing.\",\n                    max_tokens=2000,\n                ),\n                marks=[\n                    pytest.mark.cluster_gpu,\n                    pytest.mark.cluster_nvidia,\n                    pytest.mark.cluster_nvidia_roce,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-no-scheduler\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"What is KServe?\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.no_scheduler,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-simulated-dp-ep-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"This test simulates DP+EP that can run on CPU, the idea is to test the LWS-based deployment, \"\n                    \"but without the resources requirements for DP+EP (GPUs and ROCe/IB).\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_multi_node],\n            ),\n            # Scheduler config tests\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-inline-config\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-inline-config-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            # Chat completions endpoint coverage\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                        \"model-qwen2.5-0.5b\",\n                    ],\n                    model_name=\"Qwen/Qwen2.5-0.5B-Instruct\",\n                    endpoint=\"/v1/chat/completions\",\n                    prompt=\"What is KServe?\",\n                    payload_formatter=chat_completions_payload,\n                    response_assertion=create_response_assertion(with_field=\"choices\"),\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-configmap-ref\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-configmap-ref-test\",\n                    before_test=[create_scheduler_configmap],\n                    after_test=[delete_scheduler_configmap],\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-replicas\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-ha-replicas-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-custom-template\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-custom-template-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            # Scheduler v0.6 \u2192 v0.7 migration tests.\n            # Deploy v0.6-style configs and verify the controller migrates them\n            # so the v0.7 scheduler boots successfully.\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-v06-pd-config-migration\",\n                        \"workload-llmd-simulator-pd\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-v06-pd-migration-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-v06-nonzero-threshold-migration\",\n                        \"workload-llmd-simulator-pd\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-v06-threshold-migration-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Precise prefix KV cache routing test\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-precise-prefix-cache-inline-config\",\n                        \"workload-llmd-simulator-kvcache\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"precise-prefix-cache-test\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Models endpoint coverage\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/models\",\n                    response_assertion=create_response_assertion(with_field=\"data\"),\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/completions\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\"facebook/opt-125m\"),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                    peers=[\n                        TestCase(\n                            base_refs=[\n                                \"router-managed\",\n                                \"workload-llmd-simulator\",\n                                \"model-qwen2.5-0.5b\",\n                            ],\n                            endpoint=\"/v1/completions\",\n                            prompt=\"KServe is a\",\n                            payload_formatter=completions_payload,\n                            response_assertion=assert_model_field_matches(\n                                \"Qwen/Qwen2.5-0.5B-Instruct\"\n                            ),\n                            url_getter=get_model_routing_url,\n                            extra_headers={\n                                MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/Qwen/Qwen2.5-0.5B-Instruct\",\n                            },\n                        ),\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.model_routing,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/chat/completions\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/chat/completions\",\n                    prompt=\"What is KServe?\",\n                    payload_formatter=chat_completions_payload,\n                    response_assertion=assert_model_field_matches(\"facebook/opt-125m\"),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                    peers=[\n                        TestCase(\n                            base_refs=[\n                                \"router-managed\",\n                                \"workload-llmd-simulator\",\n                                \"model-qwen2.5-0.5b\",\n                            ],\n                            endpoint=\"/v1/chat/completions\",\n                            prompt=\"What is KServe?\",\n                            payload_formatter=chat_completions_payload,\n                            response_assertion=assert_model_field_matches(\n                                \"Qwen/Qwen2.5-0.5B-Instruct\"\n                            ),\n                            url_getter=get_model_routing_url,\n                            extra_headers={\n                                MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/Qwen/Qwen2.5-0.5B-Instruct\",\n                            },\n                        ),\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.model_routing,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 LoRA adapter\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m-with-lora-hf\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    model_name=f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\"\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    },\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.model_routing,\n                    pytest.mark.lora,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/models (base + LoRA)\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m-with-lora-hf\",\n                    ],\n                    endpoint=\"/v1/models\",\n                    response_assertion=assert_models_contains(\n                        \"facebook/opt-125m\",\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                        \"lora-adapter-1\",\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.model_routing,\n                    pytest.mark.lora,\n                ],\n            ),\n            # PVC storage tests -- validate direct PVC volume mount with real vLLM serving\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    response_assertion=assert_200_with_choices,\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    response_assertion=assert_200_with_choices,\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-simulated-dp-ep-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_multi_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_inference_service(test_case: TestCase):  # noqa: F811\n        inject_k8s_proxy()\n    \n        kserve_client = KServeClient(\n            config_file=os.environ.get(\"KUBECONFIG\", \"~/.kube/config\"),\n            client_configuration=client.Configuration(),\n        )\n    \n        service_name = test_case.llm_service.metadata.name\n        if not test_case.llm_service.metadata.annotations:\n            test_case.llm_service.metadata.annotations = {}\n    \n        test_case.llm_service.metadata.annotations[\n            \"security.opendatahub.io/enable-auth\"\n        ] = \"false\"\n        prefix = test_case.log_prefix\n    \n        test_failed = False\n        try:\n            print(f\"{prefix} Creating LLMInferenceService {service_name}\")\n            create_llmisvc(kserve_client, test_case.llm_service)\n            print(f\"{prefix} Waiting for LLMInferenceService {service_name} to be ready\")\n            wait_for_llm_isvc_ready(\n                kserve_client, test_case.llm_service, test_case.wait_timeout\n            )\n            print(f\"{prefix} Waiting for model response from {service_name}\")\n>           wait_for_model_response(\n                kserve_client,\n                test_case,\n                test_case.wait_timeout,\n                extra_headers=test_case.extra_headers,\n            )\n\nllmisvc/test_llm_inference_service.py:816: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f1d19fe9610>, TestCase(base_refs=['router-managed', 'workload-sin...         {'name': 'model-fb-opt-125m-with-lora-hf-c0d503b0'}]},\n 'status': None}, model_name='facebook/opt-125m'), 900)\nkwargs = {'extra_headers': {'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}}\nfunc_name = 'wait_for_model_response'\ntimestamp_start = '2026-07-07T14:47:17.842425', start_time = 1783435637.8427057\nduration = 904.6279535293579, timestamp_end = '2026-07-07T15:02:22.470662'\n\n    @functools.wraps(func)\n    def wrapper(*args, **kwargs):\n        func_name = func.__name__\n    \n        timestamp_start = datetime.now().isoformat()\n        logger.info(\n            f\"[{func_name}] [{timestamp_start}] start - args={args}, kwargs={kwargs}\"\n        )\n        start_time = time.time()\n    \n        try:\n>           result = func(*args, **kwargs)\n\nllmisvc/logging.py:40: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f1d19fe9610>\ntest_case = TestCase(base_refs=['router-managed', 'workload-single-cpu', 'model-fb-opt-125m-with-lora-hf'], prompt=None, service_n...               {'name': 'model-fb-opt-125m-with-lora-hf-c0d503b0'}]},\n 'status': None}, model_name='facebook/opt-125m')\ntimeout_seconds = 900\nextra_headers = {'X-Gateway-Model-Name': 'publishers/kserve-ci-e2e-test/models/facebook/opt-125m'}\n\n    @log_execution\n    def wait_for_model_response(\n        kserve_client: KServeClient,\n        test_case: TestCase,  # noqa: F811\n        timeout_seconds: int = 900,\n        extra_headers: Optional[Dict[str, str]] = None,\n    ) -> str:\n        def get_successful_response():\n            try:\n                if test_case.url_getter:\n                    service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n                else:\n                    service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n            except Exception as e:\n                raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n            model_url = service_url + test_case.endpoint\n    \n            headers = {\"Content-Type\": \"application/json\"}\n            if extra_headers:\n                headers.update(extra_headers)\n    \n            if test_case.payload_formatter is not None:\n                test_payload = test_case.payload_formatter(test_case)\n            elif test_case.prompt is not None:\n                test_payload = {\n                    \"model\": test_case.model_name\n                    if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                    else extra_headers[MODEL_ROUTING_HEADER],\n                    \"prompt\": test_case.prompt,\n                    \"max_tokens\": test_case.max_tokens,\n                }\n            else:\n                test_payload = None\n    \n            logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n            try:\n                if test_payload is not None:\n                    response = post_with_retry(\n                        model_url,\n                        headers=headers,\n                        json_data=test_payload,\n                        timeout=test_case.response_timeout,\n                    )\n                else:\n                    response = get_with_retry(\n                        model_url,\n                        headers=headers,\n                        timeout=test_case.response_timeout,\n                    )\n            except Exception as e:\n                logger.error(f\"\u274c Failed to call model: {e}\")\n                raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\n    \n            logger.info(f\"Model response is {response.status_code}: {response.text[:500]}\")\n    \n            if 200 <= response.status_code < 300:\n                return response\n            raise AssertionError(\n                f\"Service returned {response.status_code}: {response.text}\"\n            )\n    \n>       response = wait_for(get_successful_response, timeout=timeout_seconds, interval=5.0)\n\nllmisvc/test_llm_inference_service.py:1119: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_model_response.<locals>.get_successful_response at 0x7f1d17b737e0>\ntimeout = 900, interval = 5.0\n\n    def wait_for(\n        assertion_fn: Callable[[], Any], timeout: float = 5.0, interval: float = 0.1\n    ) -> Any:\n        \"\"\"Wait for the assertion to succeed within timeout.\"\"\"\n        deadline = time.time() + timeout\n        last_msg = None\n        while True:\n            try:\n>               return assertion_fn()\n\nllmisvc/test_llm_inference_service.py:1215: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n                response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n            else:\n                response = get_with_retry(\n                    model_url,\n                    headers=headers,\n                    timeout=test_case.response_timeout,\n                )\n        except Exception as e:\n            logger.error(f\"\u274c Failed to call model: {e}\")\n>           raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\nE           AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /v1/models (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\nllmisvc/test_llm_inference_service.py:1109: AssertionError"}, "teardown": {"duration": 0.0014952339988667518, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-custom-route-timeout-scheduler-managed-workload-single-cpu-model-fb-opt-125m]", "lineno": 244, "outcome": "failed", "keywords": ["test_llm_inference_service[router-custom-route-timeout-scheduler-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-custom-route-timeout-scheduler-managed-workload-single-cpu-model-fb-opt-125m", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.2097025599978224, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 1036.4688886540025, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/custom-route-timeout-test/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))"}, "traceback": [{"path": "llmisvc/test_llm_inference_service.py", "lineno": 816, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1119, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1215, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError"}], "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0dcd1fd0>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0dcd1fd0>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n>           response = conn.getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:534: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0dcd1fd0>\n\n    def getresponse(  # type: ignore[override]\n        self,\n    ) -> HTTPResponse:\n        \"\"\"\n        Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an instance of HTTPResponse or of whatever object is returned by the response_class variable.\n    \n        If a request has not been sent or if a previous response has not be handled, ResponseNotReady is raised. If the HTTP response indicates that the connection should be closed, then it will be closed before the response is returned. When the connection is closed, the underlying socket is closed.\n        \"\"\"\n        # Raise the same error as http.client.HTTPConnection\n        if self._response_options is None:\n            raise ResponseNotReady()\n    \n        # Reset this attribute for being used again.\n        resp_options = self._response_options\n        self._response_options = None\n    \n        # Since the connection's timeout value may have been updated\n        # we need to set the timeout on the socket.\n        self.sock.settimeout(self.timeout)\n    \n        # This is needed here to avoid circular import errors\n        from .response import HTTPResponse\n    \n        # Save a reference to the shutdown function before ownership is passed\n        # to httplib_response\n        # TODO should we implement it everywhere?\n        _shutdown = getattr(self.sock, \"shutdown\", None)\n    \n        # Get the response from http.client.HTTPConnection\n>       httplib_response = super().getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connection.py:571: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0dcd1fd0>\n\n    def getresponse(self):\n        \"\"\"Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an\n        instance of HTTPResponse or of whatever object is returned by\n        the response_class variable.\n    \n        If a request has not been sent or if a previous response has\n        not be handled, ResponseNotReady is raised.  If the HTTP\n        response indicates that the connection should be closed, then\n        it will be closed before the response is returned.  When the\n        connection is closed, the underlying socket is closed.\n        \"\"\"\n    \n        # if a prior response has been completed, then forget about it.\n        if self.__response and self.__response.isclosed():\n            self.__response = None\n    \n        # if a prior response exists, then it must be completed (otherwise, we\n        # cannot read this response's header to determine the connection-close\n        # behavior)\n        #\n        # note: if a prior response existed, but was connection-close, then the\n        # socket and response were made independent of this HTTPConnection\n        # object since a new request requires that we open a whole new\n        # connection\n        #\n        # this means the prior response had one of two states:\n        #   1) will_close: this connection was reset and the prior socket and\n        #                  response operate independently\n        #   2) persistent: the response was retained and we await its\n        #                  isclosed() status to become true.\n        #\n        if self.__state != _CS_REQ_SENT or self.__response:\n            raise ResponseNotReady(self.__state)\n    \n        if self.debuglevel > 0:\n            response = self.response_class(self.sock, self.debuglevel,\n                                           method=self._method)\n        else:\n            response = self.response_class(self.sock, method=self._method)\n    \n        try:\n            try:\n>               response.begin()\n\n/usr/lib64/python3.11/http/client.py:1395: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f4f0de74850>\n\n    def begin(self):\n        if self.headers is not None:\n            # we've already started reading the response\n            return\n    \n        # read until we get a non-100 response\n        while True:\n>           version, status, reason = self._read_status()\n\n/usr/lib64/python3.11/http/client.py:325: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f4f0de74850>\n\n    def _read_status(self):\n>       line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n\n/usr/lib64/python3.11/http/client.py:286: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <socket.SocketIO object at 0x7f4f0de756f0>\nb = <memory at 0x7f4f0d2c44c0>\n\n    def readinto(self, b):\n        \"\"\"Read up to len(b) bytes into the writable buffer *b* and return\n        the number of bytes read.  If the socket is non-blocking and no bytes\n        are available, None is returned.\n    \n        If *b* is non-empty, a 0 return value indicates that the connection\n        was shutdown at the other end.\n        \"\"\"\n        self._checkClosed()\n        self._checkReadable()\n        if self._timeout_occurred:\n            raise OSError(\"cannot read from timed out object\")\n        while True:\n            try:\n>               return self._sock.recv_into(b)\nE               TimeoutError: timed out\n\n/usr/lib64/python3.11/socket.py:718: TimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n>           response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:787: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0dcd1fd0>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f4f0dcd1fd0>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n            response = conn.getresponse()\n        except (BaseSSLError, OSError) as e:\n>           self._raise_timeout(err=e, url=url, timeout_value=read_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:536: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nerr = TimeoutError('timed out')\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\ntimeout_value = 60\n\n    def _raise_timeout(\n        self,\n        err: BaseSSLError | OSError | SocketTimeout,\n        url: str,\n        timeout_value: _TYPE_TIMEOUT | None,\n    ) -> None:\n        \"\"\"Is the error actually a timeout? Will raise a ReadTimeout or pass\"\"\"\n    \n        if isinstance(err, SocketTimeout):\n>           raise ReadTimeoutError(\n                self, url, f\"Read timed out. (read timeout={timeout_value})\"\n            ) from err\nE           urllib3.exceptions.ReadTimeoutError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:367: ReadTimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <requests.adapters.HTTPAdapter object at 0x7f4f0dc80690>\nrequest = <PreparedRequest [POST]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n>           resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:667: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=7, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=6, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=5, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=4, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=3, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=2, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=1, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = RemoteDisconnected('Remote end closed connection without response')\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n>           retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:841: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nmethod = 'POST'\nurl = '/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nresponse = None\nerror = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\n_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f4f0dc80410>\n_stacktrace = <traceback object at 0x7f4f0dcd2e40>\n\n    def increment(\n        self,\n        method: str | None = None,\n        url: str | None = None,\n        response: BaseHTTPResponse | None = None,\n        error: Exception | None = None,\n        _pool: ConnectionPool | None = None,\n        _stacktrace: TracebackType | None = None,\n    ) -> Self:\n        \"\"\"Return a new Retry object with incremented retry counters.\n    \n        :param response: A response object, or None, if the server did not\n            return a response.\n        :type response: :class:`~urllib3.response.BaseHTTPResponse`\n        :param Exception error: An error encountered during the request, or\n            None if the response was received successfully.\n    \n        :return: A new ``Retry`` object.\n        \"\"\"\n        if self.total is False and error:\n            # Disabled, indicate to re-raise the error.\n            raise reraise(type(error), error, _stacktrace)\n    \n        total = self.total\n        if total is not None:\n            total -= 1\n    \n        connect = self.connect\n        read = self.read\n        redirect = self.redirect\n        status_count = self.status\n        other = self.other\n        cause = \"unknown\"\n        status = None\n        redirect_location = None\n    \n        if error and self._is_connection_error(error):\n            # Connect retry?\n            if connect is False:\n                raise reraise(type(error), error, _stacktrace)\n            elif connect is not None:\n                connect -= 1\n    \n        elif error and self._is_read_error(error):\n            # Read retry?\n            if read is False or method is None or not self._is_method_retryable(method):\n                raise reraise(type(error), error, _stacktrace)\n            elif read is not None:\n                read -= 1\n    \n        elif error:\n            # Other retry?\n            if other is not None:\n                other -= 1\n    \n        elif response and response.get_redirect_location():\n            # Redirect retry?\n            if redirect is not None:\n                redirect -= 1\n            cause = \"too many redirects\"\n            response_redirect_location = response.get_redirect_location()\n            if response_redirect_location:\n                redirect_location = response_redirect_location\n            status = response.status\n    \n        else:\n            # Incrementing because of a server error like a 500 in\n            # status_forcelist and the given method is in the allowed_methods\n            cause = ResponseError.GENERIC_ERROR\n            if response and response.status:\n                if status_count is not None:\n                    status_count -= 1\n                cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)\n                status = response.status\n    \n        history = self.history + (\n            RequestHistory(method, url, error, status, redirect_location),\n        )\n    \n        new_retry = self.new(\n            total=total,\n            connect=connect,\n            read=read,\n            redirect=redirect,\n            status=status_count,\n            other=other,\n            history=history,\n        )\n    \n        if new_retry.is_exhausted():\n            reason = error or ResponseError(cause)\n>           raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]\nE           urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/custom-route-timeout-test/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/util/retry.py:519: MaxRetryError\n\nDuring handling of the above exception, another exception occurred:\n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n>               response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n\nllmisvc/test_llm_inference_service.py:1095: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\n\n    def post_with_retry(\n        url: str,\n        *,\n        headers: Dict = None,\n        json_data: Union[Dict, List] = None,\n        data: Union[str, bytes] = None,\n        stream: bool = False,\n        timeout: float = None,\n        total_retries: int = DEFAULT_RETRY_TOTAL,\n        backoff_factor: float = DEFAULT_RETRY_BACKOFF_FACTOR,\n        retry_status_codes=DEFAULT_RETRY_STATUS_CODES,\n    ) -> requests.Response:\n        \"\"\"\n        Send POST request with retries for transient HTTP and network failures.\n        \"\"\"\n        if json_data is not None and data is not None:\n            raise ValueError(\"Only one of json_data or data can be provided.\")\n    \n        with _retry_session(\n            [\"POST\"], total_retries, backoff_factor, retry_status_codes\n        ) as session:\n>           return session.post(\n                url,\n                json=json_data,\n                data=data,\n                headers=headers,\n                stream=stream,\n                timeout=timeout,\n            )\n\ncommon/http_retry.py:70: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f4f0da4e750>\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\ndata = None\njson = {'max_tokens': 20, 'model': 'facebook/opt-125m', 'prompt': 'KServe is a'}\nkwargs = {'headers': {'Content-Type': 'application/json'}, 'stream': False, 'timeout': 60}\n\n    def post(self, url, data=None, json=None, **kwargs):\n        r\"\"\"Sends a POST request. Returns :class:`Response` object.\n    \n        :param url: URL for the new :class:`Request` object.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the :class:`Request`.\n        :param \\*\\*kwargs: Optional arguments that ``request`` takes.\n        :rtype: requests.Response\n        \"\"\"\n    \n>       return self.request(\"POST\", url, data=data, json=json, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:637: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f4f0da4e750>, method = 'POST'\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/custom-route-timeout-test/v1/completions'\nparams = None, data = None, headers = {'Content-Type': 'application/json'}\ncookies = None, files = None, auth = None, timeout = 60, allow_redirects = True\nproxies = {}, hooks = None, stream = False, verify = None, cert = None\njson = {'max_tokens': 20, 'model': 'facebook/opt-125m', 'prompt': 'KServe is a'}\n\n    def request(\n        self,\n        method,\n        url,\n        params=None,\n        data=None,\n        headers=None,\n        cookies=None,\n        files=None,\n        auth=None,\n        timeout=None,\n        allow_redirects=True,\n        proxies=None,\n        hooks=None,\n        stream=None,\n        verify=None,\n        cert=None,\n        json=None,\n    ):\n        \"\"\"Constructs a :class:`Request <Request>`, prepares it and sends it.\n        Returns :class:`Response <Response>` object.\n    \n        :param method: method for the new :class:`Request` object.\n        :param url: URL for the new :class:`Request` object.\n        :param params: (optional) Dictionary or bytes to be sent in the query\n            string for the :class:`Request`.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the\n            :class:`Request`.\n        :param headers: (optional) Dictionary of HTTP Headers to send with the\n            :class:`Request`.\n        :param cookies: (optional) Dict or CookieJar object to send with the\n            :class:`Request`.\n        :param files: (optional) Dictionary of ``'filename': file-like-objects``\n            for multipart encoding upload.\n        :param auth: (optional) Auth tuple or callable to enable\n            Basic/Digest/Custom HTTP Auth.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple\n        :param allow_redirects: (optional) Set to True by default.\n        :type allow_redirects: bool\n        :param proxies: (optional) Dictionary mapping protocol or protocol and\n            hostname to the URL of the proxy.\n        :param hooks: (optional) Dictionary mapping hook name to one event or\n            list of events, event must be callable.\n        :param stream: (optional) whether to immediately download the response\n            content. Defaults to ``False``.\n        :param verify: (optional) Either a boolean, in which case it controls whether we verify\n            the server's TLS certificate, or a string, in which case it must be a path\n            to a CA bundle to use. Defaults to ``True``. When set to\n            ``False``, requests will accept any TLS certificate presented by\n            the server, and will ignore hostname mismatches and/or expired\n            certificates, which will make your application vulnerable to\n            man-in-the-middle (MitM) attacks. Setting verify to ``False``\n            may be useful during local development or testing.\n        :param cert: (optional) if String, path to ssl client cert file (.pem).\n            If Tuple, ('cert', 'key') pair.\n        :rtype: requests.Response\n        \"\"\"\n        # Create the Request.\n        req = Request(\n            method=method.upper(),\n            url=url,\n            headers=headers,\n            files=files,\n            data=data or {},\n            json=json,\n            params=params or {},\n            auth=auth,\n            cookies=cookies,\n            hooks=hooks,\n        )\n        prep = self.prepare_request(req)\n    \n        proxies = proxies or {}\n    \n        settings = self.merge_environment_settings(\n            prep.url, proxies, stream, verify, cert\n        )\n    \n        # Send the request.\n        send_kwargs = {\n            \"timeout\": timeout,\n            \"allow_redirects\": allow_redirects,\n        }\n        send_kwargs.update(settings)\n>       resp = self.send(prep, **send_kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:589: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f4f0da4e750>\nrequest = <PreparedRequest [POST]>\nkwargs = {'cert': None, 'proxies': OrderedDict(), 'stream': False, 'timeout': 60, ...}\nallow_redirects = True, stream = False, hooks = {'response': []}\nadapter = <requests.adapters.HTTPAdapter object at 0x7f4f0dc80690>\nstart = 1783435858.5349567\n\n    def send(self, request, **kwargs):\n        \"\"\"Send a given PreparedRequest.\n    \n        :rtype: requests.Response\n        \"\"\"\n        # Set defaults that the hooks can utilize to ensure they always have\n        # the correct parameters to reproduce the previous request.\n        kwargs.setdefault(\"stream\", self.stream)\n        kwargs.setdefault(\"verify\", self.verify)\n        kwargs.setdefault(\"cert\", self.cert)\n        if \"proxies\" not in kwargs:\n            kwargs[\"proxies\"] = resolve_proxies(request, self.proxies, self.trust_env)\n    \n        # It's possible that users might accidentally send a Request object.\n        # Guard against that specific failure case.\n        if isinstance(request, Request):\n            raise ValueError(\"You can only send PreparedRequests.\")\n    \n        # Set up variables needed for resolve_redirects and dispatching of hooks\n        allow_redirects = kwargs.pop(\"allow_redirects\", True)\n        stream = kwargs.get(\"stream\")\n        hooks = request.hooks\n    \n        # Get the appropriate adapter to use\n        adapter = self.get_adapter(url=request.url)\n    \n        # Start time (approximately) of the request\n        start = preferred_clock()\n    \n        # Send the request\n>       r = adapter.send(request, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:703: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.adapters.HTTPAdapter object at 0x7f4f0dc80690>\nrequest = <PreparedRequest [POST]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n            resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n    \n        except (ProtocolError, OSError) as err:\n            raise ConnectionError(err, request=request)\n    \n        except MaxRetryError as e:\n            if isinstance(e.reason, ConnectTimeoutError):\n                # TODO: Remove this in 3.0.0: see #2811\n                if not isinstance(e.reason, NewConnectionError):\n                    raise ConnectTimeout(e, request=request)\n    \n            if isinstance(e.reason, ResponseError):\n                raise RetryError(e, request=request)\n    \n            if isinstance(e.reason, _ProxyError):\n                raise ProxyError(e, request=request)\n    \n            if isinstance(e.reason, _SSLError):\n                # This branch is for urllib3 v1.22 and later.\n                raise SSLError(e, request=request)\n    \n>           raise ConnectionError(e, request=request)\nE           requests.exceptions.ConnectionError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/custom-route-timeout-test/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:700: ConnectionError\n\nThe above exception was the direct cause of the following exception:\n\ntest_case = TestCase(base_refs=['router-custom-route-timeout', 'scheduler-managed', 'workload-single-cpu', 'model-fb-opt-125m'], p...               {'name': 'model-fb-opt-125m-custom-route-928a8601'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.llminferenceservice\n    @pytest.mark.asyncio(loop_scope=\"session\")\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-gateway-ref\",\n                        \"router-with-managed-route\",\n                        \"model-fb-opt-125m\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=create_response_assertion(with_field=\"choices\"),\n                    expected_gateway=ROUTER_GATEWAYS[0],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[0]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-custom-route-timeout\",\n                        \"scheduler-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"custom-route-timeout-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-refs\",\n                        \"scheduler-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"router-with-refs-test\",\n                    expected_gateway=ROUTER_GATEWAYS[0],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[0]],\n                            routes=[ROUTER_ROUTES[0], ROUTER_ROUTES[1]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\"router-managed\", \"workload-pd-cpu\", \"model-fb-opt-125m\"],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-custom-route-timeout-pd\",\n                        \"scheduler-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    service_name=\"custom-route-timeout-pd-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-with-refs-pd\",\n                        \"scheduler-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"You are an expert in Kubernetes-native machine learning serving platforms, with deep knowledge of the KServe project. \"\n                    \"Explain the challenges of serving large-scale models, GPU scheduling, and how KServe integrates with capabilities like multi-model serving. \"\n                    \"Provide a detailed comparison with open source alternatives, focusing on operational trade-offs.\",\n                    service_name=\"router-with-refs-pd-test\",\n                    response_assertion=assert_200_with_choices,\n                    expected_gateway=ROUTER_GATEWAYS[1],\n                    before_test=[\n                        lambda: create_router_resources(\n                            gateways=[ROUTER_GATEWAYS[1]],\n                            routes=[ROUTER_ROUTES[2], ROUTER_ROUTES[3]],\n                        )\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.custom_gateway,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-dp-ep-gpu\",\n                        \"workload-dp-ep-prefill-gpu\",\n                        \"model-deepseek-v2-lite\",\n                    ],\n                    prompt=\"Delve into the multifaceted implications of a fully disaggregated cloud architecture, specifically \"\n                    \"where the compute plane (P) and the data plane (D) are independently deployed and managed for a \"\n                    \"geographically distributed, high-throughput, low-latency microservices ecosystem. Beyond the \"\n                    \"fundamental challenges of network latency and data consistency, elaborate on the advanced \"\n                    \"considerations and trade-offs inherent in such a setup: 1. Network Architecture and Protocols: \"\n                    \"How would the network fabric and underlying protocols (e.g., RDMA, custom transport layers) need to \"\n                    \"evolve to support optimal performance and minimize inter-plane communication overhead, especially for \"\n                    \"synchronous operations? Discuss the role of network programmability (e.g., SDN, P4) in dynamically \"\n                    \"optimizing routing and traffic flow between P and D. 2. Advanced Data Consistency and Durability: \"\n                    \"Explore sophisticated data consistency models (e.g., causal consistency, strong eventual consistency) \"\n                    \"and their applicability in balancing performance and data integrity across a globally distributed data plane. \"\n                    \"Detail strategies for ensuring data durability and fault tolerance, including multi-region replication, \"\n                    \"intelligent partitioning, and recovery mechanisms in the event of partial or full plane failures. \"\n                    \"3. Dynamic Resource Orchestration and Cost Optimization: Analyze how an orchestration layer would intelligently \"\n                    \"manage the independent scaling of compute (P) and data (D) resources, considering fluctuating workloads, \"\n                    \"cost efficiency, and performance targets (e.g., using predictive analytics for resource provisioning). \"\n                    \"Discuss mechanisms for dynamically reallocating compute nodes to different data partitions based on \"\n                    \"workload patterns and data locality, potentially involving live migration strategies. \"\n                    \"4. Security and Compliance in a Distributed Landscape: Address the enhanced security perimeter \"\n                    \"challenges, including securing communication channels between P and D (encryption in transit, mutual TLS), \"\n                    \"fine-grained access control to data at rest and in motion, and identity management across disaggregated \"\n                    \"components. Discuss how such an architecture impacts compliance with regulatory frameworks (e.g., GDPR, HIPAA) \"\n                    \"concerning data sovereignty, privacy, and auditability. 5. Operational Complexity and Observability: \"\n                    \"Examine the increased complexity in monitoring, logging, and tracing across highly decoupled compute and \"\n                    \"data planes. What specialized tooling and practices (e.g., distributed tracing with OpenTelemetry, advanced AIOps) \"\n                    \"would be essential? How would incident response and troubleshooting differ in this disaggregated environment \"\n                    \"compared to traditional integrated systems? Consider the challenges of pinpointing root causes across \"\n                    \"independent failures. 6. Real-world Applicability and Future Trends: Identify specific industries \"\n                    \"or use cases (e.g., high-frequency trading, IoT edge processing, large language model inference) \"\n                    \"where the benefits of P/D disaggregation would strongly outweigh its complexities. \"\n                    \"Conclude by speculating on emerging technologies or paradigms (e.g., serverless compute functions \"\n                    \"directly interacting with object storage, in-memory disaggregation) that could further drive or \"\n                    \"transform P/D disaggregation in cloud computing.\",\n                    max_tokens=2000,\n                ),\n                marks=[\n                    pytest.mark.cluster_gpu,\n                    pytest.mark.cluster_nvidia,\n                    pytest.mark.cluster_nvidia_roce,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-no-scheduler\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"What is KServe?\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.no_scheduler,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-simulated-dp-ep-cpu\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"This test simulates DP+EP that can run on CPU, the idea is to test the LWS-based deployment, \"\n                    \"but without the resources requirements for DP+EP (GPUs and ROCe/IB).\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_multi_node],\n            ),\n            # Scheduler config tests\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-inline-config\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-inline-config-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            # Chat completions endpoint coverage\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                        \"model-qwen2.5-0.5b\",\n                    ],\n                    model_name=\"Qwen/Qwen2.5-0.5B-Instruct\",\n                    endpoint=\"/v1/chat/completions\",\n                    prompt=\"What is KServe?\",\n                    payload_formatter=chat_completions_payload,\n                    response_assertion=create_response_assertion(with_field=\"choices\"),\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-configmap-ref\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-configmap-ref-test\",\n                    before_test=[create_scheduler_configmap],\n                    after_test=[delete_scheduler_configmap],\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-replicas\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-ha-replicas-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-custom-template\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-custom-template-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n            # Scheduler v0.6 \u2192 v0.7 migration tests.\n            # Deploy v0.6-style configs and verify the controller migrates them\n            # so the v0.7 scheduler boots successfully.\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-v06-pd-config-migration\",\n                        \"workload-llmd-simulator-pd\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-v06-pd-migration-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-v06-nonzero-threshold-migration\",\n                        \"workload-llmd-simulator-pd\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"scheduler-v06-threshold-migration-test\",\n                    response_assertion=assert_200_with_choices,\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Precise prefix KV cache routing test\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-precise-prefix-cache-inline-config\",\n                        \"workload-llmd-simulator-kvcache\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"precise-prefix-cache-test\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Models endpoint coverage\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/models\",\n                    response_assertion=create_response_assertion(with_field=\"data\"),\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/completions\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\"facebook/opt-125m\"),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                    peers=[\n                        TestCase(\n                            base_refs=[\n                                \"router-managed\",\n                                \"workload-llmd-simulator\",\n                                \"model-qwen2.5-0.5b\",\n                            ],\n                            endpoint=\"/v1/completions\",\n                            prompt=\"KServe is a\",\n                            payload_formatter=completions_payload,\n                            response_assertion=assert_model_field_matches(\n                                \"Qwen/Qwen2.5-0.5B-Instruct\"\n                            ),\n                            url_getter=get_model_routing_url,\n                            extra_headers={\n                                MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/Qwen/Qwen2.5-0.5B-Instruct\",\n                            },\n                        ),\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.model_routing,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/chat/completions\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                    ],\n                    endpoint=\"/v1/chat/completions\",\n                    prompt=\"What is KServe?\",\n                    payload_formatter=chat_completions_payload,\n                    response_assertion=assert_model_field_matches(\"facebook/opt-125m\"),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                    peers=[\n                        TestCase(\n                            base_refs=[\n                                \"router-managed\",\n                                \"workload-llmd-simulator\",\n                                \"model-qwen2.5-0.5b\",\n                            ],\n                            endpoint=\"/v1/chat/completions\",\n                            prompt=\"What is KServe?\",\n                            payload_formatter=chat_completions_payload,\n                            response_assertion=assert_model_field_matches(\n                                \"Qwen/Qwen2.5-0.5B-Instruct\"\n                            ),\n                            url_getter=get_model_routing_url,\n                            extra_headers={\n                                MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/Qwen/Qwen2.5-0.5B-Instruct\",\n                            },\n                        ),\n                    ],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                    pytest.mark.model_routing,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 LoRA adapter\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m-with-lora-hf\",\n                    ],\n                    endpoint=\"/v1/completions\",\n                    prompt=\"KServe is a\",\n                    model_name=f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\"\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    },\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.model_routing,\n                    pytest.mark.lora,\n                ],\n            ),\n            # Model-based routing via X-Gateway-Model-Name header \u2014 /v1/models (base + LoRA)\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-fb-opt-125m-with-lora-hf\",\n                    ],\n                    endpoint=\"/v1/models\",\n                    response_assertion=assert_models_contains(\n                        \"facebook/opt-125m\",\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                        \"lora-adapter-1\",\n                        f\"publishers/{KSERVE_TEST_NAMESPACE}/models/lora-adapter-1\",\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: f\"publishers/{KSERVE_TEST_NAMESPACE}/models/facebook/opt-125m\",\n                    },\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.model_routing,\n                    pytest.mark.lora,\n                ],\n            ),\n            # PVC storage tests -- validate direct PVC volume mount with real vLLM serving\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-single-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    response_assertion=assert_200_with_choices,\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-pd-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    response_assertion=assert_200_with_choices,\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-simulated-dp-ep-cpu\",\n                        \"model-pvc\",\n                    ],\n                    prompt=\"KServe is a\",\n                    before_test=[ensure_pvc_with_model],\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_multi_node,\n                    pytest.mark.pvc_storage,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_inference_service(test_case: TestCase):  # noqa: F811\n        inject_k8s_proxy()\n    \n        kserve_client = KServeClient(\n            config_file=os.environ.get(\"KUBECONFIG\", \"~/.kube/config\"),\n            client_configuration=client.Configuration(),\n        )\n    \n        service_name = test_case.llm_service.metadata.name\n        if not test_case.llm_service.metadata.annotations:\n            test_case.llm_service.metadata.annotations = {}\n    \n        test_case.llm_service.metadata.annotations[\n            \"security.opendatahub.io/enable-auth\"\n        ] = \"false\"\n        prefix = test_case.log_prefix\n    \n        test_failed = False\n        try:\n            print(f\"{prefix} Creating LLMInferenceService {service_name}\")\n            create_llmisvc(kserve_client, test_case.llm_service)\n            print(f\"{prefix} Waiting for LLMInferenceService {service_name} to be ready\")\n            wait_for_llm_isvc_ready(\n                kserve_client, test_case.llm_service, test_case.wait_timeout\n            )\n            print(f\"{prefix} Waiting for model response from {service_name}\")\n>           wait_for_model_response(\n                kserve_client,\n                test_case,\n                test_case.wait_timeout,\n                extra_headers=test_case.extra_headers,\n            )\n\nllmisvc/test_llm_inference_service.py:816: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f4f0dcefcd0>, TestCase(base_refs=['router-custom-route-timeout', ...         {'name': 'model-fb-opt-125m-custom-route-928a8601'}]},\n 'status': None}, model_name='facebook/opt-125m'), 900)\nkwargs = {'extra_headers': None}, func_name = 'wait_for_model_response'\ntimestamp_start = '2026-07-07T14:50:58.433371', start_time = 1783435858.4336658\nduration = 904.6219441890717, timestamp_end = '2026-07-07T15:06:03.055613'\n\n    @functools.wraps(func)\n    def wrapper(*args, **kwargs):\n        func_name = func.__name__\n    \n        timestamp_start = datetime.now().isoformat()\n        logger.info(\n            f\"[{func_name}] [{timestamp_start}] start - args={args}, kwargs={kwargs}\"\n        )\n        start_time = time.time()\n    \n        try:\n>           result = func(*args, **kwargs)\n\nllmisvc/logging.py:40: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f4f0dcefcd0>\ntest_case = TestCase(base_refs=['router-custom-route-timeout', 'scheduler-managed', 'workload-single-cpu', 'model-fb-opt-125m'], p...               {'name': 'model-fb-opt-125m-custom-route-928a8601'}]},\n 'status': None}, model_name='facebook/opt-125m')\ntimeout_seconds = 900, extra_headers = None\n\n    @log_execution\n    def wait_for_model_response(\n        kserve_client: KServeClient,\n        test_case: TestCase,  # noqa: F811\n        timeout_seconds: int = 900,\n        extra_headers: Optional[Dict[str, str]] = None,\n    ) -> str:\n        def get_successful_response():\n            try:\n                if test_case.url_getter:\n                    service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n                else:\n                    service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n            except Exception as e:\n                raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n            model_url = service_url + test_case.endpoint\n    \n            headers = {\"Content-Type\": \"application/json\"}\n            if extra_headers:\n                headers.update(extra_headers)\n    \n            if test_case.payload_formatter is not None:\n                test_payload = test_case.payload_formatter(test_case)\n            elif test_case.prompt is not None:\n                test_payload = {\n                    \"model\": test_case.model_name\n                    if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                    else extra_headers[MODEL_ROUTING_HEADER],\n                    \"prompt\": test_case.prompt,\n                    \"max_tokens\": test_case.max_tokens,\n                }\n            else:\n                test_payload = None\n    \n            logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n            try:\n                if test_payload is not None:\n                    response = post_with_retry(\n                        model_url,\n                        headers=headers,\n                        json_data=test_payload,\n                        timeout=test_case.response_timeout,\n                    )\n                else:\n                    response = get_with_retry(\n                        model_url,\n                        headers=headers,\n                        timeout=test_case.response_timeout,\n                    )\n            except Exception as e:\n                logger.error(f\"\u274c Failed to call model: {e}\")\n                raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\n    \n            logger.info(f\"Model response is {response.status_code}: {response.text[:500]}\")\n    \n            if 200 <= response.status_code < 300:\n                return response\n            raise AssertionError(\n                f\"Service returned {response.status_code}: {response.text}\"\n            )\n    \n>       response = wait_for(get_successful_response, timeout=timeout_seconds, interval=5.0)\n\nllmisvc/test_llm_inference_service.py:1119: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_model_response.<locals>.get_successful_response at 0x7f4f0db94860>\ntimeout = 900, interval = 5.0\n\n    def wait_for(\n        assertion_fn: Callable[[], Any], timeout: float = 5.0, interval: float = 0.1\n    ) -> Any:\n        \"\"\"Wait for the assertion to succeed within timeout.\"\"\"\n        deadline = time.time() + timeout\n        last_msg = None\n        while True:\n            try:\n>               return assertion_fn()\n\nllmisvc/test_llm_inference_service.py:1215: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n                response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n            else:\n                response = get_with_retry(\n                    model_url,\n                    headers=headers,\n                    timeout=test_case.response_timeout,\n                )\n        except Exception as e:\n            logger.error(f\"\u274c Failed to call model: {e}\")\n>           raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\nE           AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/custom-route-timeout-test/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\nllmisvc/test_llm_inference_service.py:1109: AssertionError"}, "teardown": {"duration": 0.0016857009977684356, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-single-cpu-model-pvc]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-single-cpu-model-pvc]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "pvc_storage", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-pvc", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 20.339041892999376, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 542.9436347640003, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0017272769982810132, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-with-refs-scheduler-managed-workload-single-cpu-model-fb-opt-125m]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-with-refs-scheduler-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "custom_gateway", "__wrapped__", "pytestmark", "router-with-refs-scheduler-managed-workload-single-cpu-model-fb-opt-125m", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 2.607739945000503, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 168.98871667099593, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.004098746998351999, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-pd-cpu-model-fb-opt-125m]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-pd-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-pd-cpu-model-fb-opt-125m", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.13161521400616039, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 606.5796367889998, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.008482855002512224, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-pd-cpu-model-pvc]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-pd-cpu-model-pvc]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "pvc_storage", "__wrapped__", "pytestmark", "router-managed-workload-pd-cpu-model-pvc", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.22460024199972395, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 394.75346705899574, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0033666189992800355, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_multi_node-router-managed-workload-simulated-dp-ep-cpu-model-pvc]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-simulated-dp-ep-cpu-model-pvc]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_multi_node", "pvc_storage", "__wrapped__", "pytestmark", "router-managed-workload-simulated-dp-ep-cpu-model-pvc", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.3527561200025957, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 495.42933738000283, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.004307780000090133, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 1.0511263110020082, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 303.83352623099927, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0037093150021973997, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-with-refs-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-with-refs-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "custom_gateway", "__wrapped__", "pytestmark", "router-with-refs-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 2.6419733180009644, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 238.63155522899615, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0035368570024729706, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_conversion.py::TestLLMInferenceServiceConversion::test_v1alpha1_to_v1alpha2_conversion", "lineno": 212, "outcome": "passed", "keywords": ["test_v1alpha1_to_v1alpha2_conversion", "cluster_single_node", "cluster_cpu", "pytestmark", "TestLLMInferenceServiceConversion", "conversion", "llminferenceservice", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.013701073999982327, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.43288581300294027, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.10592688000178896, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_conversion.py::TestLLMInferenceServiceConversion::test_v1alpha2_to_v1alpha1_conversion", "lineno": 303, "outcome": "passed", "keywords": ["test_v1alpha2_to_v1alpha1_conversion", "cluster_single_node", "cluster_cpu", "pytestmark", "TestLLMInferenceServiceConversion", "conversion", "llminferenceservice", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.012982145002752077, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.11347488100000191, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.01536428699910175, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_conversion.py::TestLLMInferenceServiceConversion::test_criticality_preservation_via_annotations", "lineno": 394, "outcome": "passed", "keywords": ["test_criticality_preservation_via_annotations", "cluster_single_node", "cluster_cpu", "pytestmark", "TestLLMInferenceServiceConversion", "conversion", "llminferenceservice", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.012301826005568728, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.12013125300290994, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04876670100202318, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_conversion.py::TestLLMInferenceServiceConversion::test_lora_criticality_preservation", "lineno": 531, "outcome": "passed", "keywords": ["test_lora_criticality_preservation", "cluster_single_node", "cluster_cpu", "pytestmark", "TestLLMInferenceServiceConversion", "conversion", "llminferenceservice", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.012551560997962952, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.14637634799873922, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0408147070047562, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_conversion.py::TestLLMInferenceServiceConversion::test_round_trip_conversion_preserves_fields", "lineno": 680, "outcome": "passed", "keywords": ["test_round_trip_conversion_preserves_fields", "cluster_single_node", "cluster_cpu", "pytestmark", "TestLLMInferenceServiceConversion", "conversion", "llminferenceservice", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.012356119994365145, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.0940753289978602, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0997259439973277, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_stop.py::test_llm_stop_feature[cluster_cpu-cluster_single_node-router-managed-workload-single-cpu-model-fb-opt-125m]", "lineno": 39, "outcome": "passed", "keywords": ["test_llm_stop_feature[router-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m", "test_llm_inference_service_stop.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.15166655299981358, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 303.5893462480017, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0021523730029002763, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-no-scheduler-workload-single-cpu-model-fb-opt-125m]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-no-scheduler-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "no_scheduler", "__wrapped__", "pytestmark", "router-no-scheduler-workload-single-cpu-model-fb-opt-125m", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.17566775000159396, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 161.29917781000404, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.00211738700454589, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_multi_node-router-managed-workload-simulated-dp-ep-cpu-model-fb-opt-125m]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-simulated-dp-ep-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_multi_node", "__wrapped__", "pytestmark", "router-managed-workload-simulated-dp-ep-cpu-model-fb-opt-125m", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1448500670012436, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 226.01655121799558, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.003835663002973888, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_lora_adapters.py::test_llm_with_lora_adapters[cluster_cpu-single-lora-adapter-hf]", "lineno": 203, "outcome": "passed", "keywords": ["test_llm_with_lora_adapters[single-lora-adapter-hf]", "parametrize", "llminferenceservice", "cluster_cpu", "lora", "__wrapped__", "pytestmark", "single-lora-adapter-hf", "test_llm_lora_adapters.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.0006456970004364848, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 152.15380833299423, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.002386442996794358, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_lora_adapters.py::test_llm_with_lora_adapters[cluster_cpu-multiple-lora-adapters]", "lineno": 203, "outcome": "passed", "keywords": ["test_llm_with_lora_adapters[multiple-lora-adapters]", "parametrize", "llminferenceservice", "cluster_cpu", "lora", "__wrapped__", "pytestmark", "multiple-lora-adapters", "test_llm_lora_adapters.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.0003376989989192225, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 189.32327749600518, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0038503449977724813, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-scheduler-with-inline-config-workload-llmd-simulator]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-inline-config-workload-llmd-simulator]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-scheduler-with-inline-config-workload-llmd-simulator", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.5915024930000072, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 91.95491287099867, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.001955537998583168, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-workload-llmd-simulator-model-qwen2.5-0.5b]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-llmd-simulator-model-qwen2.5-0.5b]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-model-qwen2.5-0.5b", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.14317626700358232, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 79.68359418099863, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.001869924002676271, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_tls.py::test_llm_tls_resources[cluster_cpu-cluster_single_node-router-managed-workload-single-cpu-model-fb-opt-125m]", "lineno": 92, "outcome": "passed", "keywords": ["test_llm_tls_resources[router-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m", "test_llm_tls.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1152606809991994, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 163.1232960299967, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0019243269998696633, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-scheduler-with-configmap-ref-workload-llmd-simulator]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-configmap-ref-workload-llmd-simulator]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-scheduler-with-configmap-ref-workload-llmd-simulator", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.31723685700126225, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 97.19377598699793, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.043889649998163804, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-scheduler-with-replicas-workload-llmd-simulator]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-replicas-workload-llmd-simulator]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-scheduler-with-replicas-workload-llmd-simulator", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1350880500031053, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 67.37841170799948, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0027484509992063977, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_prestop_hook.py::test_prestop_hook[cluster_cpu-cluster_single_node-router-managed-workload-single-cpu-model-fb-opt-125m]", "lineno": 40, "outcome": "passed", "keywords": ["test_prestop_hook[router-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m", "test_prestop_hook.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.11943004000204382, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 255.6712410359978, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.006145991996163502, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-scheduler-with-custom-template-workload-llmd-simulator]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-custom-template-workload-llmd-simulator]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-scheduler-with-custom-template-workload-llmd-simulator", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.5211051829974167, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 110.32942087599804, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0017419069990864955, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-scheduler-v06-pd-config-migration-workload-llmd-simulator-pd]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-v06-pd-config-migration-workload-llmd-simulator-pd]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-scheduler-v06-pd-config-migration-workload-llmd-simulator-pd", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.13727888399444055, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 105.36714657500124, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.002730242005782202, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service.py::test_llm_inference_service[cluster_cpu-cluster_single_node-router-managed-scheduler-v06-nonzero-threshold-migration-workload-llmd-simulator-pd]", "lineno": 244, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-v06-nonzero-threshold-migration-workload-llmd-simulator-pd]", "parametrize", "asyncio", "llminferenceservice", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-scheduler-v06-nonzero-threshold-migration-workload-llmd-simulator-pd", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.18091580400505336, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 86.8416553499992, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.004038194994791411, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_rolling_upgrade.py::test_rolling_upgrade_coordination[cluster_cpu-cluster_single_node-router-managed-workload-llmd-simulator-model-fb-opt-125m]", "lineno": 40, "outcome": "failed", "keywords": ["test_rolling_upgrade_coordination[router-managed-workload-llmd-simulator-model-fb-opt-125m]", "parametrize", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-model-fb-opt-125m", "llmd_simulator", "test_rolling_upgrade.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.14016271400032565, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 948.9967083320007, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/rolling-upgrade-test/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))"}, "traceback": [{"path": "llmisvc/test_rolling_upgrade.py", "lineno": 125, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1119, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1215, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1109, "message": "AssertionError"}], "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d179bc350>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d179bc350>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n>           response = conn.getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:534: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d179bc350>\n\n    def getresponse(  # type: ignore[override]\n        self,\n    ) -> HTTPResponse:\n        \"\"\"\n        Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an instance of HTTPResponse or of whatever object is returned by the response_class variable.\n    \n        If a request has not been sent or if a previous response has not be handled, ResponseNotReady is raised. If the HTTP response indicates that the connection should be closed, then it will be closed before the response is returned. When the connection is closed, the underlying socket is closed.\n        \"\"\"\n        # Raise the same error as http.client.HTTPConnection\n        if self._response_options is None:\n            raise ResponseNotReady()\n    \n        # Reset this attribute for being used again.\n        resp_options = self._response_options\n        self._response_options = None\n    \n        # Since the connection's timeout value may have been updated\n        # we need to set the timeout on the socket.\n        self.sock.settimeout(self.timeout)\n    \n        # This is needed here to avoid circular import errors\n        from .response import HTTPResponse\n    \n        # Save a reference to the shutdown function before ownership is passed\n        # to httplib_response\n        # TODO should we implement it everywhere?\n        _shutdown = getattr(self.sock, \"shutdown\", None)\n    \n        # Get the response from http.client.HTTPConnection\n>       httplib_response = super().getresponse()\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connection.py:571: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d179bc350>\n\n    def getresponse(self):\n        \"\"\"Get the response from the server.\n    \n        If the HTTPConnection is in the correct state, returns an\n        instance of HTTPResponse or of whatever object is returned by\n        the response_class variable.\n    \n        If a request has not been sent or if a previous response has\n        not be handled, ResponseNotReady is raised.  If the HTTP\n        response indicates that the connection should be closed, then\n        it will be closed before the response is returned.  When the\n        connection is closed, the underlying socket is closed.\n        \"\"\"\n    \n        # if a prior response has been completed, then forget about it.\n        if self.__response and self.__response.isclosed():\n            self.__response = None\n    \n        # if a prior response exists, then it must be completed (otherwise, we\n        # cannot read this response's header to determine the connection-close\n        # behavior)\n        #\n        # note: if a prior response existed, but was connection-close, then the\n        # socket and response were made independent of this HTTPConnection\n        # object since a new request requires that we open a whole new\n        # connection\n        #\n        # this means the prior response had one of two states:\n        #   1) will_close: this connection was reset and the prior socket and\n        #                  response operate independently\n        #   2) persistent: the response was retained and we await its\n        #                  isclosed() status to become true.\n        #\n        if self.__state != _CS_REQ_SENT or self.__response:\n            raise ResponseNotReady(self.__state)\n    \n        if self.debuglevel > 0:\n            response = self.response_class(self.sock, self.debuglevel,\n                                           method=self._method)\n        else:\n            response = self.response_class(self.sock, method=self._method)\n    \n        try:\n            try:\n>               response.begin()\n\n/usr/lib64/python3.11/http/client.py:1395: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f1d17dde710>\n\n    def begin(self):\n        if self.headers is not None:\n            # we've already started reading the response\n            return\n    \n        # read until we get a non-100 response\n        while True:\n>           version, status, reason = self._read_status()\n\n/usr/lib64/python3.11/http/client.py:325: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <http.client.HTTPResponse object at 0x7f1d17dde710>\n\n    def _read_status(self):\n>       line = str(self.fp.readline(_MAXLINE + 1), \"iso-8859-1\")\n\n/usr/lib64/python3.11/http/client.py:286: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <socket.SocketIO object at 0x7f1d17ddeb90>\nb = <memory at 0x7f1d17859780>\n\n    def readinto(self, b):\n        \"\"\"Read up to len(b) bytes into the writable buffer *b* and return\n        the number of bytes read.  If the socket is non-blocking and no bytes\n        are available, None is returned.\n    \n        If *b* is non-empty, a 0 return value indicates that the connection\n        was shutdown at the other end.\n        \"\"\"\n        self._checkClosed()\n        self._checkReadable()\n        if self._timeout_occurred:\n            raise OSError(\"cannot read from timed out object\")\n        while True:\n            try:\n>               return self._sock.recv_into(b)\nE               TimeoutError: timed out\n\n/usr/lib64/python3.11/socket.py:718: TimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n>           response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:787: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nconn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d179bc350>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\ntimeout = Timeout(connect=60, read=60, total=None), chunked = False\nresponse_conn = <HTTPConnection(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80) at 0x7f1d179bc350>\npreload_content = False, decode_content = False, enforce_content_length = True\n\n    def _make_request(\n        self,\n        conn: BaseHTTPConnection,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | None = None,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        chunked: bool = False,\n        response_conn: BaseHTTPConnection | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        enforce_content_length: bool = True,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Perform a request on a given urllib connection object taken from our\n        pool.\n    \n        :param conn:\n            a connection from one of our connection pools\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            Pass ``None`` to retry until you receive a response. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param response_conn:\n            Set this to ``None`` if you will handle releasing the connection or\n            set the connection to have the response release it.\n    \n        :param preload_content:\n          If True, the response's body will be preloaded during construction.\n    \n        :param decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param enforce_content_length:\n            Enforce content length checking. Body returned by server must match\n            value of Content-Length header, if present. Otherwise, raise error.\n        \"\"\"\n        self.num_requests += 1\n    \n        timeout_obj = self._get_timeout(timeout)\n        timeout_obj.start_connect()\n        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)\n    \n        try:\n            # Trigger any extra validation we need to do.\n            try:\n                self._validate_conn(conn)\n            except (SocketTimeout, BaseSSLError) as e:\n                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)\n                raise\n    \n        # _validate_conn() starts the connection to an HTTPS proxy\n        # so we need to wrap errors with 'ProxyError' here too.\n        except (\n            OSError,\n            NewConnectionError,\n            TimeoutError,\n            BaseSSLError,\n            CertificateError,\n            SSLError,\n        ) as e:\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            # If the connection didn't successfully connect to it's proxy\n            # then there\n            if isinstance(\n                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            raise new_e\n    \n        # conn.request() calls http.client.*.request, not the method in\n        # urllib3.request. It also calls makefile (recv) on the socket.\n        try:\n            conn.request(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                enforce_content_length=enforce_content_length,\n            )\n    \n        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is\n        # legitimately able to close the connection after sending a valid response.\n        # With this behaviour, the received response is still readable.\n        except BrokenPipeError:\n            pass\n        except OSError as e:\n            # MacOS/Linux\n            # EPROTOTYPE and ECONNRESET are needed on macOS\n            # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/\n            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.\n            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:\n                raise\n    \n        # Reset the timeout for the recv() on the socket\n        read_timeout = timeout_obj.read_timeout\n    \n        if not conn.is_closed:\n            # In Python 3 socket.py will catch EAGAIN and return None when you\n            # try and read into the file pointer created by http.client, which\n            # instead raises a BadStatusLine exception. Instead of catching\n            # the exception and assuming all BadStatusLine exceptions are read\n            # timeouts, check for a zero timeout before making the request.\n            if read_timeout == 0:\n                raise ReadTimeoutError(\n                    self, url, f\"Read timed out. (read timeout={read_timeout})\"\n                )\n            conn.timeout = read_timeout\n    \n        # Receive the response from the server\n        try:\n            response = conn.getresponse()\n        except (BaseSSLError, OSError) as e:\n>           self._raise_timeout(err=e, url=url, timeout_value=read_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:536: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nerr = TimeoutError('timed out')\nurl = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\ntimeout_value = 60\n\n    def _raise_timeout(\n        self,\n        err: BaseSSLError | OSError | SocketTimeout,\n        url: str,\n        timeout_value: _TYPE_TIMEOUT | None,\n    ) -> None:\n        \"\"\"Is the error actually a timeout? Will raise a ReadTimeout or pass\"\"\"\n    \n        if isinstance(err, SocketTimeout):\n>           raise ReadTimeoutError(\n                self, url, f\"Read timed out. (read timeout={timeout_value})\"\n            ) from err\nE           urllib3.exceptions.ReadTimeoutError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:367: ReadTimeoutError\n\nThe above exception was the direct cause of the following exception:\n\nself = <requests.adapters.HTTPAdapter object at 0x7f1d16e82850>\nrequest = <PreparedRequest [POST]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n>           resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:667: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=7, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=6, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=5, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=4, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=3, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=2, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=1, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False\nerr = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\nclean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n            retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n            retries.sleep()\n    \n            # Keep track of the error for the retry warning.\n            err = e\n    \n        finally:\n            if not clean_exit:\n                # We hit some kind of exception, handled or otherwise. We need\n                # to throw the connection away unless explicitly told not to.\n                # Close the connection, set the variable to None, and make sure\n                # we put the None back in the pool to avoid leaking it.\n                if conn:\n                    conn.close()\n                    conn = None\n                release_this_conn = True\n    \n            if release_this_conn:\n                # Put the connection back to be reused. If the connection is\n                # expired then it will be None, which will get replaced with a\n                # fresh connection during _get_conn.\n                self._put_conn(conn)\n    \n        if not conn:\n            # Try again\n            log.warning(\n                \"Retrying (%r) after connection broken by '%r': %s\", retries, err, url\n            )\n>           return self.urlopen(\n                method,\n                url,\n                body,\n                headers,\n                retries,\n                redirect,\n                assert_same_host,\n                timeout=timeout,\n                pool_timeout=pool_timeout,\n                release_conn=release_conn,\n                chunked=chunked,\n                body_pos=body_pos,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:871: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nbody = b'{\"model\": \"facebook/opt-125m\", \"prompt\": \"KServe is a\", \"max_tokens\": 20}'\nheaders = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'Content-Length': '73'}\nretries = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nredirect = False, assert_same_host = False\ntimeout = Timeout(connect=60, read=60, total=None), pool_timeout = None\nrelease_conn = False, chunked = False, body_pos = None, preload_content = False\ndecode_content = False, response_kw = {}\nparsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions', query=None, fragment=None)\ndestination_scheme = None, conn = None, release_this_conn = True\nhttp_tunnel_required = False, err = None, clean_exit = False\n\n    def urlopen(  # type: ignore[override]\n        self,\n        method: str,\n        url: str,\n        body: _TYPE_BODY | None = None,\n        headers: typing.Mapping[str, str] | None = None,\n        retries: Retry | bool | int | None = None,\n        redirect: bool = True,\n        assert_same_host: bool = True,\n        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,\n        pool_timeout: int | None = None,\n        release_conn: bool | None = None,\n        chunked: bool = False,\n        body_pos: _TYPE_BODY_POSITION | None = None,\n        preload_content: bool = True,\n        decode_content: bool = True,\n        **response_kw: typing.Any,\n    ) -> BaseHTTPResponse:\n        \"\"\"\n        Get a connection from the pool and perform an HTTP request. This is the\n        lowest level call for making a request, so you'll need to specify all\n        the raw details.\n    \n        .. note::\n    \n           More commonly, it's appropriate to use a convenience method\n           such as :meth:`request`.\n    \n        .. note::\n    \n           `release_conn` will only behave as expected if\n           `preload_content=False` because we want to make\n           `preload_content=False` the default behaviour someday soon without\n           breaking backwards compatibility.\n    \n        :param method:\n            HTTP request method (such as GET, POST, PUT, etc.)\n    \n        :param url:\n            The URL to perform the request on.\n    \n        :param body:\n            Data to send in the request body, either :class:`str`, :class:`bytes`,\n            an iterable of :class:`str`/:class:`bytes`, or a file-like object.\n    \n        :param headers:\n            Dictionary of custom headers to send, such as User-Agent,\n            If-None-Match, etc. If None, pool headers are used. If provided,\n            these headers completely replace any pool-specific headers.\n    \n        :param retries:\n            Configure the number of retries to allow before raising a\n            :class:`~urllib3.exceptions.MaxRetryError` exception.\n    \n            If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a\n            :class:`~urllib3.util.retry.Retry` object for fine-grained control\n            over different types of retries.\n            Pass an integer number to retry connection errors that many times,\n            but no other types of errors. Pass zero to never retry.\n    \n            If ``False``, then retries are disabled and any exception is raised\n            immediately. Also, instead of raising a MaxRetryError on redirects,\n            the redirect response will be returned.\n    \n        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.\n    \n        :param redirect:\n            If True, automatically handle redirects (status codes 301, 302,\n            303, 307, 308). Each redirect counts as a retry. Disabling retries\n            will disable redirect, too.\n    \n        :param assert_same_host:\n            If ``True``, will make sure that the host of the pool requests is\n            consistent else will raise HostChangedError. When ``False``, you can\n            use the pool on an HTTP proxy and request foreign hosts.\n    \n        :param timeout:\n            If specified, overrides the default timeout for this one\n            request. It may be a float (in seconds) or an instance of\n            :class:`urllib3.util.Timeout`.\n    \n        :param pool_timeout:\n            If set and the pool is set to block=True, then this method will\n            block for ``pool_timeout`` seconds and raise EmptyPoolError if no\n            connection is available within the time period.\n    \n        :param bool preload_content:\n            If True, the response's body will be preloaded into memory.\n    \n        :param bool decode_content:\n            If True, will attempt to decode the body based on the\n            'content-encoding' header.\n    \n        :param release_conn:\n            If False, then the urlopen call will not release the connection\n            back into the pool once a response is received (but will release if\n            you read the entire contents of the response such as when\n            `preload_content=True`). This is useful if you're not preloading\n            the response's content immediately. You will need to call\n            ``r.release_conn()`` on the response ``r`` to return the connection\n            back into the pool. If None, it takes the value of ``preload_content``\n            which defaults to ``True``.\n    \n        :param bool chunked:\n            If True, urllib3 will send the body using chunked transfer\n            encoding. Otherwise, urllib3 will send the body using the standard\n            content-length form. Defaults to False.\n    \n        :param int body_pos:\n            Position to seek to in file-like body in the event of a retry or\n            redirect. Typically this won't need to be set because urllib3 will\n            auto-populate the value when needed.\n        \"\"\"\n        parsed_url = parse_url(url)\n        destination_scheme = parsed_url.scheme\n    \n        if headers is None:\n            headers = self.headers\n    \n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n    \n        if release_conn is None:\n            release_conn = preload_content\n    \n        # Check host\n        if assert_same_host and not self.is_same_host(url):\n            raise HostChangedError(self, url, retries)\n    \n        # Ensure that the URL we're connecting to is properly encoded\n        if url.startswith(\"/\"):\n            url = to_str(_encode_target(url))\n        else:\n            url = to_str(parsed_url.url)\n    \n        conn = None\n    \n        # Track whether `conn` needs to be released before\n        # returning/raising/recursing. Update this variable if necessary, and\n        # leave `release_conn` constant throughout the function. That way, if\n        # the function recurses, the original value of `release_conn` will be\n        # passed down into the recursive call, and its value will be respected.\n        #\n        # See issue #651 [1] for details.\n        #\n        # [1] <https://github.com/urllib3/urllib3/issues/651>\n        release_this_conn = release_conn\n    \n        http_tunnel_required = connection_requires_http_tunnel(\n            self.proxy, self.proxy_config, destination_scheme\n        )\n    \n        # Merge the proxy headers. Only done when not using HTTP CONNECT. We\n        # have to copy the headers dict so we can safely change it without those\n        # changes being reflected in anyone else's copy.\n        if not http_tunnel_required:\n            headers = headers.copy()  # type: ignore[attr-defined]\n            headers.update(self.proxy_headers)  # type: ignore[union-attr]\n    \n        # Must keep the exception bound to a separate variable or else Python 3\n        # complains about UnboundLocalError.\n        err = None\n    \n        # Keep track of whether we cleanly exited the except block. This\n        # ensures we do proper cleanup in finally.\n        clean_exit = False\n    \n        # Rewind body position, if needed. Record current position\n        # for future rewinds in the event of a redirect/retry.\n        body_pos = set_file_position(body, body_pos)\n    \n        try:\n            # Request a connection from the queue.\n            timeout_obj = self._get_timeout(timeout)\n            conn = self._get_conn(timeout=pool_timeout)\n    \n            conn.timeout = timeout_obj.connect_timeout  # type: ignore[assignment]\n    \n            # Is this a closed/new connection that requires CONNECT tunnelling?\n            if self.proxy is not None and http_tunnel_required and conn.is_closed:\n                try:\n                    self._prepare_proxy(conn)\n                except (BaseSSLError, OSError, SocketTimeout) as e:\n                    self._raise_timeout(\n                        err=e, url=self.proxy.url, timeout_value=conn.timeout\n                    )\n                    raise\n    \n            # If we're going to release the connection in ``finally:``, then\n            # the response doesn't need to know about the connection. Otherwise\n            # it will also try to release it and we'll have a double-release\n            # mess.\n            response_conn = conn if not release_conn else None\n    \n            # Make the request on the HTTPConnection object\n            response = self._make_request(\n                conn,\n                method,\n                url,\n                timeout=timeout_obj,\n                body=body,\n                headers=headers,\n                chunked=chunked,\n                retries=retries,\n                response_conn=response_conn,\n                preload_content=preload_content,\n                decode_content=decode_content,\n                **response_kw,\n            )\n    \n            # Everything went great!\n            clean_exit = True\n    \n        except EmptyPoolError:\n            # Didn't get a connection from the pool, no need to clean up\n            clean_exit = True\n            release_this_conn = False\n            raise\n    \n        except (\n            TimeoutError,\n            HTTPException,\n            OSError,\n            ProtocolError,\n            BaseSSLError,\n            SSLError,\n            CertificateError,\n            ProxyError,\n        ) as e:\n            # Discard the connection for these exceptions. It will be\n            # replaced during the next _get_conn() call.\n            clean_exit = False\n            new_e: Exception = e\n            if isinstance(e, (BaseSSLError, CertificateError)):\n                new_e = SSLError(e)\n            if isinstance(\n                new_e,\n                (\n                    OSError,\n                    NewConnectionError,\n                    TimeoutError,\n                    SSLError,\n                    HTTPException,\n                ),\n            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):\n                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n            elif isinstance(new_e, (OSError, HTTPException)):\n                new_e = ProtocolError(\"Connection aborted.\", new_e)\n    \n>           retries = retries.increment(\n                method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]\n            )\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/connectionpool.py:841: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = Retry(total=0, connect=None, read=None, redirect=None, status=None)\nmethod = 'POST', url = '/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nresponse = None\nerror = ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\")\n_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f1d16e82f10>\n_stacktrace = <traceback object at 0x7f1d174e2900>\n\n    def increment(\n        self,\n        method: str | None = None,\n        url: str | None = None,\n        response: BaseHTTPResponse | None = None,\n        error: Exception | None = None,\n        _pool: ConnectionPool | None = None,\n        _stacktrace: TracebackType | None = None,\n    ) -> Self:\n        \"\"\"Return a new Retry object with incremented retry counters.\n    \n        :param response: A response object, or None, if the server did not\n            return a response.\n        :type response: :class:`~urllib3.response.BaseHTTPResponse`\n        :param Exception error: An error encountered during the request, or\n            None if the response was received successfully.\n    \n        :return: A new ``Retry`` object.\n        \"\"\"\n        if self.total is False and error:\n            # Disabled, indicate to re-raise the error.\n            raise reraise(type(error), error, _stacktrace)\n    \n        total = self.total\n        if total is not None:\n            total -= 1\n    \n        connect = self.connect\n        read = self.read\n        redirect = self.redirect\n        status_count = self.status\n        other = self.other\n        cause = \"unknown\"\n        status = None\n        redirect_location = None\n    \n        if error and self._is_connection_error(error):\n            # Connect retry?\n            if connect is False:\n                raise reraise(type(error), error, _stacktrace)\n            elif connect is not None:\n                connect -= 1\n    \n        elif error and self._is_read_error(error):\n            # Read retry?\n            if read is False or method is None or not self._is_method_retryable(method):\n                raise reraise(type(error), error, _stacktrace)\n            elif read is not None:\n                read -= 1\n    \n        elif error:\n            # Other retry?\n            if other is not None:\n                other -= 1\n    \n        elif response and response.get_redirect_location():\n            # Redirect retry?\n            if redirect is not None:\n                redirect -= 1\n            cause = \"too many redirects\"\n            response_redirect_location = response.get_redirect_location()\n            if response_redirect_location:\n                redirect_location = response_redirect_location\n            status = response.status\n    \n        else:\n            # Incrementing because of a server error like a 500 in\n            # status_forcelist and the given method is in the allowed_methods\n            cause = ResponseError.GENERIC_ERROR\n            if response and response.status:\n                if status_count is not None:\n                    status_count -= 1\n                cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)\n                status = response.status\n    \n        history = self.history + (\n            RequestHistory(method, url, error, status, redirect_location),\n        )\n    \n        new_retry = self.new(\n            total=total,\n            connect=connect,\n            read=read,\n            redirect=redirect,\n            status=status_count,\n            other=other,\n            history=history,\n        )\n    \n        if new_retry.is_exhausted():\n            reason = error or ResponseError(cause)\n>           raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]\nE           urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/rolling-upgrade-test/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/urllib3/util/retry.py:519: MaxRetryError\n\nDuring handling of the above exception, another exception occurred:\n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n>               response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n\nllmisvc/test_llm_inference_service.py:1095: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\n\n    def post_with_retry(\n        url: str,\n        *,\n        headers: Dict = None,\n        json_data: Union[Dict, List] = None,\n        data: Union[str, bytes] = None,\n        stream: bool = False,\n        timeout: float = None,\n        total_retries: int = DEFAULT_RETRY_TOTAL,\n        backoff_factor: float = DEFAULT_RETRY_BACKOFF_FACTOR,\n        retry_status_codes=DEFAULT_RETRY_STATUS_CODES,\n    ) -> requests.Response:\n        \"\"\"\n        Send POST request with retries for transient HTTP and network failures.\n        \"\"\"\n        if json_data is not None and data is not None:\n            raise ValueError(\"Only one of json_data or data can be provided.\")\n    \n        with _retry_session(\n            [\"POST\"], total_retries, backoff_factor, retry_status_codes\n        ) as session:\n>           return session.post(\n                url,\n                json=json_data,\n                data=data,\n                headers=headers,\n                stream=stream,\n                timeout=timeout,\n            )\n\ncommon/http_retry.py:70: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d17479090>\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\ndata = None\njson = {'max_tokens': 20, 'model': 'facebook/opt-125m', 'prompt': 'KServe is a'}\nkwargs = {'headers': {'Content-Type': 'application/json'}, 'stream': False, 'timeout': 60}\n\n    def post(self, url, data=None, json=None, **kwargs):\n        r\"\"\"Sends a POST request. Returns :class:`Response` object.\n    \n        :param url: URL for the new :class:`Request` object.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the :class:`Request`.\n        :param \\*\\*kwargs: Optional arguments that ``request`` takes.\n        :rtype: requests.Response\n        \"\"\"\n    \n>       return self.request(\"POST\", url, data=data, json=json, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:637: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d17479090>, method = 'POST'\nurl = 'http://ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com/kserve-ci-e2e-test/rolling-upgrade-test/v1/completions'\nparams = None, data = None, headers = {'Content-Type': 'application/json'}\ncookies = None, files = None, auth = None, timeout = 60, allow_redirects = True\nproxies = {}, hooks = None, stream = False, verify = None, cert = None\njson = {'max_tokens': 20, 'model': 'facebook/opt-125m', 'prompt': 'KServe is a'}\n\n    def request(\n        self,\n        method,\n        url,\n        params=None,\n        data=None,\n        headers=None,\n        cookies=None,\n        files=None,\n        auth=None,\n        timeout=None,\n        allow_redirects=True,\n        proxies=None,\n        hooks=None,\n        stream=None,\n        verify=None,\n        cert=None,\n        json=None,\n    ):\n        \"\"\"Constructs a :class:`Request <Request>`, prepares it and sends it.\n        Returns :class:`Response <Response>` object.\n    \n        :param method: method for the new :class:`Request` object.\n        :param url: URL for the new :class:`Request` object.\n        :param params: (optional) Dictionary or bytes to be sent in the query\n            string for the :class:`Request`.\n        :param data: (optional) Dictionary, list of tuples, bytes, or file-like\n            object to send in the body of the :class:`Request`.\n        :param json: (optional) json to send in the body of the\n            :class:`Request`.\n        :param headers: (optional) Dictionary of HTTP Headers to send with the\n            :class:`Request`.\n        :param cookies: (optional) Dict or CookieJar object to send with the\n            :class:`Request`.\n        :param files: (optional) Dictionary of ``'filename': file-like-objects``\n            for multipart encoding upload.\n        :param auth: (optional) Auth tuple or callable to enable\n            Basic/Digest/Custom HTTP Auth.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple\n        :param allow_redirects: (optional) Set to True by default.\n        :type allow_redirects: bool\n        :param proxies: (optional) Dictionary mapping protocol or protocol and\n            hostname to the URL of the proxy.\n        :param hooks: (optional) Dictionary mapping hook name to one event or\n            list of events, event must be callable.\n        :param stream: (optional) whether to immediately download the response\n            content. Defaults to ``False``.\n        :param verify: (optional) Either a boolean, in which case it controls whether we verify\n            the server's TLS certificate, or a string, in which case it must be a path\n            to a CA bundle to use. Defaults to ``True``. When set to\n            ``False``, requests will accept any TLS certificate presented by\n            the server, and will ignore hostname mismatches and/or expired\n            certificates, which will make your application vulnerable to\n            man-in-the-middle (MitM) attacks. Setting verify to ``False``\n            may be useful during local development or testing.\n        :param cert: (optional) if String, path to ssl client cert file (.pem).\n            If Tuple, ('cert', 'key') pair.\n        :rtype: requests.Response\n        \"\"\"\n        # Create the Request.\n        req = Request(\n            method=method.upper(),\n            url=url,\n            headers=headers,\n            files=files,\n            data=data or {},\n            json=json,\n            params=params or {},\n            auth=auth,\n            cookies=cookies,\n            hooks=hooks,\n        )\n        prep = self.prepare_request(req)\n    \n        proxies = proxies or {}\n    \n        settings = self.merge_environment_settings(\n            prep.url, proxies, stream, verify, cert\n        )\n    \n        # Send the request.\n        send_kwargs = {\n            \"timeout\": timeout,\n            \"allow_redirects\": allow_redirects,\n        }\n        send_kwargs.update(settings)\n>       resp = self.send(prep, **send_kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:589: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.sessions.Session object at 0x7f1d17479090>\nrequest = <PreparedRequest [POST]>\nkwargs = {'cert': None, 'proxies': OrderedDict(), 'stream': False, 'timeout': 60, ...}\nallow_redirects = True, stream = False, hooks = {'response': []}\nadapter = <requests.adapters.HTTPAdapter object at 0x7f1d16e82850>\nstart = 1783439108.7332075\n\n    def send(self, request, **kwargs):\n        \"\"\"Send a given PreparedRequest.\n    \n        :rtype: requests.Response\n        \"\"\"\n        # Set defaults that the hooks can utilize to ensure they always have\n        # the correct parameters to reproduce the previous request.\n        kwargs.setdefault(\"stream\", self.stream)\n        kwargs.setdefault(\"verify\", self.verify)\n        kwargs.setdefault(\"cert\", self.cert)\n        if \"proxies\" not in kwargs:\n            kwargs[\"proxies\"] = resolve_proxies(request, self.proxies, self.trust_env)\n    \n        # It's possible that users might accidentally send a Request object.\n        # Guard against that specific failure case.\n        if isinstance(request, Request):\n            raise ValueError(\"You can only send PreparedRequests.\")\n    \n        # Set up variables needed for resolve_redirects and dispatching of hooks\n        allow_redirects = kwargs.pop(\"allow_redirects\", True)\n        stream = kwargs.get(\"stream\")\n        hooks = request.hooks\n    \n        # Get the appropriate adapter to use\n        adapter = self.get_adapter(url=request.url)\n    \n        # Start time (approximately) of the request\n        start = preferred_clock()\n    \n        # Send the request\n>       r = adapter.send(request, **kwargs)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/sessions.py:703: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <requests.adapters.HTTPAdapter object at 0x7f1d16e82850>\nrequest = <PreparedRequest [POST]>, stream = False\ntimeout = Timeout(connect=60, read=60, total=None), verify = '/tmp/ca.crt'\ncert = None, proxies = OrderedDict()\n\n    def send(\n        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None\n    ):\n        \"\"\"Sends PreparedRequest object. Returns Response object.\n    \n        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.\n        :param stream: (optional) Whether to stream the request content.\n        :param timeout: (optional) How long to wait for the server to send\n            data before giving up, as a float, or a :ref:`(connect timeout,\n            read timeout) <timeouts>` tuple.\n        :type timeout: float or tuple or urllib3 Timeout object\n        :param verify: (optional) Either a boolean, in which case it controls whether\n            we verify the server's TLS certificate, or a string, in which case it\n            must be a path to a CA bundle to use\n        :param cert: (optional) Any user-provided SSL certificate to be trusted.\n        :param proxies: (optional) The proxies dictionary to apply to the request.\n        :rtype: requests.Response\n        \"\"\"\n    \n        try:\n            conn = self.get_connection_with_tls_context(\n                request, verify, proxies=proxies, cert=cert\n            )\n        except LocationValueError as e:\n            raise InvalidURL(e, request=request)\n    \n        self.cert_verify(conn, request.url, verify, cert)\n        url = self.request_url(request, proxies)\n        self.add_headers(\n            request,\n            stream=stream,\n            timeout=timeout,\n            verify=verify,\n            cert=cert,\n            proxies=proxies,\n        )\n    \n        chunked = not (request.body is None or \"Content-Length\" in request.headers)\n    \n        if isinstance(timeout, tuple):\n            try:\n                connect, read = timeout\n                timeout = TimeoutSauce(connect=connect, read=read)\n            except ValueError:\n                raise ValueError(\n                    f\"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, \"\n                    f\"or a single float to set both timeouts to the same value.\"\n                )\n        elif isinstance(timeout, TimeoutSauce):\n            pass\n        else:\n            timeout = TimeoutSauce(connect=timeout, read=timeout)\n    \n        try:\n            resp = conn.urlopen(\n                method=request.method,\n                url=url,\n                body=request.body,\n                headers=request.headers,\n                redirect=False,\n                assert_same_host=False,\n                preload_content=False,\n                decode_content=False,\n                retries=self.max_retries,\n                timeout=timeout,\n                chunked=chunked,\n            )\n    \n        except (ProtocolError, OSError) as err:\n            raise ConnectionError(err, request=request)\n    \n        except MaxRetryError as e:\n            if isinstance(e.reason, ConnectTimeoutError):\n                # TODO: Remove this in 3.0.0: see #2811\n                if not isinstance(e.reason, NewConnectionError):\n                    raise ConnectTimeout(e, request=request)\n    \n            if isinstance(e.reason, ResponseError):\n                raise RetryError(e, request=request)\n    \n            if isinstance(e.reason, _ProxyError):\n                raise ProxyError(e, request=request)\n    \n            if isinstance(e.reason, _SSLError):\n                # This branch is for urllib3 v1.22 and later.\n                raise SSLError(e, request=request)\n    \n>           raise ConnectionError(e, request=request)\nE           requests.exceptions.ConnectionError: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/rolling-upgrade-test/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/requests/adapters.py:700: ConnectionError\n\nThe above exception was the direct cause of the following exception:\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator', 'model-fb-opt-125m'], prompt='KServe is a', service_n...              {'name': 'model-fb-opt-125m-rolling-upgra-30e65219'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.llminferenceservice\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator\",\n                        \"model-fb-opt-125m\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"rolling-upgrade-test\",\n                ),\n                marks=[pytest.mark.cluster_cpu, pytest.mark.cluster_single_node],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_rolling_upgrade_coordination(test_case: TestCase):\n        \"\"\"\n        Verify the service recovers cleanly after a workload rolling update.\n    \n        Triggers a rolling update by patching a pod-template annotation on the\n        LLMInferenceService. After the rollout completes the workload Deployment\n        must be Available and the overall service must be Ready and able to serve\n        inference requests \u2014 confirming the workload-before-EPP update ordering\n        left the system in a healthy state.\n        \"\"\"\n        inject_k8s_proxy()\n    \n        kserve_client = KServeClient(\n            config_file=os.environ.get(\"KUBECONFIG\", \"~/.kube/config\"),\n            client_configuration=client.Configuration(),\n        )\n    \n        service_name = test_case.llm_service.metadata.name\n        namespace = test_case.llm_service.metadata.namespace\n        test_failed = False\n    \n        if not test_case.llm_service.metadata.annotations:\n            test_case.llm_service.metadata.annotations = {}\n        test_case.llm_service.metadata.annotations[\n            \"security.opendatahub.io/enable-auth\"\n        ] = \"false\"\n    \n        try:\n            print(f\"Creating LLMInferenceService {service_name}\")\n            create_llmisvc(kserve_client, test_case.llm_service)\n    \n            print(f\"Waiting for {service_name} to be ready\")\n            wait_for_llm_isvc_ready(\n                kserve_client, test_case.llm_service, test_case.wait_timeout\n            )\n    \n            apps_v1 = client.AppsV1Api()\n            workload_name = f\"{service_name}-kserve\"\n    \n            initial = apps_v1.read_namespaced_deployment(workload_name, namespace)\n            initial_generation = initial.metadata.generation\n            print(f\"Workload Deployment initial generation: {initial_generation}\")\n    \n            print(\"Triggering workload rolling update via pod-template annotation patch\")\n            _patch_rolling_update_trigger(kserve_client, test_case.llm_service)\n    \n            print(\"Waiting for workload rollout to start (generation increment)\")\n            wait_for_rollout_started(\n                apps_v1, workload_name, namespace, initial_generation, timeout_seconds=60\n            )\n    \n            print(\"Waiting for workload rollout to complete (Deployment Available)\")\n            wait_for_deployment_available(\n                apps_v1, workload_name, namespace, timeout_seconds=120\n            )\n            print(\"Workload rollout complete\")\n    \n            print(f\"Waiting for {service_name} to be Ready after rollout\")\n            wait_for_llm_isvc_ready(\n                kserve_client, test_case.llm_service, test_case.wait_timeout\n            )\n    \n            print(\"Verifying inference still works after rolling update\")\n>           wait_for_model_response(kserve_client, test_case, test_case.wait_timeout)\n\nllmisvc/test_rolling_upgrade.py:125: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f1d174f2950>, TestCase(base_refs=['router-managed', 'workload-llm...        {'name': 'model-fb-opt-125m-rolling-upgra-30e65219'}]},\n 'status': None}, model_name='facebook/opt-125m'), 900)\nkwargs = {}, func_name = 'wait_for_model_response'\ntimestamp_start = '2026-07-07T15:45:08.690808', start_time = 1783439108.691052\nduration = 904.6563992500305, timestamp_end = '2026-07-07T16:00:13.347454'\n\n    @functools.wraps(func)\n    def wrapper(*args, **kwargs):\n        func_name = func.__name__\n    \n        timestamp_start = datetime.now().isoformat()\n        logger.info(\n            f\"[{func_name}] [{timestamp_start}] start - args={args}, kwargs={kwargs}\"\n        )\n        start_time = time.time()\n    \n        try:\n>           result = func(*args, **kwargs)\n\nllmisvc/logging.py:40: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f1d174f2950>\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator', 'model-fb-opt-125m'], prompt='KServe is a', service_n...              {'name': 'model-fb-opt-125m-rolling-upgra-30e65219'}]},\n 'status': None}, model_name='facebook/opt-125m')\ntimeout_seconds = 900, extra_headers = None\n\n    @log_execution\n    def wait_for_model_response(\n        kserve_client: KServeClient,\n        test_case: TestCase,  # noqa: F811\n        timeout_seconds: int = 900,\n        extra_headers: Optional[Dict[str, str]] = None,\n    ) -> str:\n        def get_successful_response():\n            try:\n                if test_case.url_getter:\n                    service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n                else:\n                    service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n            except Exception as e:\n                raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n            model_url = service_url + test_case.endpoint\n    \n            headers = {\"Content-Type\": \"application/json\"}\n            if extra_headers:\n                headers.update(extra_headers)\n    \n            if test_case.payload_formatter is not None:\n                test_payload = test_case.payload_formatter(test_case)\n            elif test_case.prompt is not None:\n                test_payload = {\n                    \"model\": test_case.model_name\n                    if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                    else extra_headers[MODEL_ROUTING_HEADER],\n                    \"prompt\": test_case.prompt,\n                    \"max_tokens\": test_case.max_tokens,\n                }\n            else:\n                test_payload = None\n    \n            logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n            try:\n                if test_payload is not None:\n                    response = post_with_retry(\n                        model_url,\n                        headers=headers,\n                        json_data=test_payload,\n                        timeout=test_case.response_timeout,\n                    )\n                else:\n                    response = get_with_retry(\n                        model_url,\n                        headers=headers,\n                        timeout=test_case.response_timeout,\n                    )\n            except Exception as e:\n                logger.error(f\"\u274c Failed to call model: {e}\")\n                raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\n    \n            logger.info(f\"Model response is {response.status_code}: {response.text[:500]}\")\n    \n            if 200 <= response.status_code < 300:\n                return response\n            raise AssertionError(\n                f\"Service returned {response.status_code}: {response.text}\"\n            )\n    \n>       response = wait_for(get_successful_response, timeout=timeout_seconds, interval=5.0)\n\nllmisvc/test_llm_inference_service.py:1119: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_model_response.<locals>.get_successful_response at 0x7f1d17b70040>\ntimeout = 900, interval = 5.0\n\n    def wait_for(\n        assertion_fn: Callable[[], Any], timeout: float = 5.0, interval: float = 0.1\n    ) -> Any:\n        \"\"\"Wait for the assertion to succeed within timeout.\"\"\"\n        deadline = time.time() + timeout\n        last_msg = None\n        while True:\n            try:\n>               return assertion_fn()\n\nllmisvc/test_llm_inference_service.py:1215: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def get_successful_response():\n        try:\n            if test_case.url_getter:\n                service_url = test_case.url_getter(kserve_client, test_case.llm_service)\n            else:\n                service_url = get_llm_service_url(kserve_client, test_case.llm_service)\n        except Exception as e:\n            raise AssertionError(f\"\u274c Failed to get service URL: {e}\") from e\n    \n        model_url = service_url + test_case.endpoint\n    \n        headers = {\"Content-Type\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n    \n        if test_case.payload_formatter is not None:\n            test_payload = test_case.payload_formatter(test_case)\n        elif test_case.prompt is not None:\n            test_payload = {\n                \"model\": test_case.model_name\n                if not extra_headers or MODEL_ROUTING_HEADER not in extra_headers\n                else extra_headers[MODEL_ROUTING_HEADER],\n                \"prompt\": test_case.prompt,\n                \"max_tokens\": test_case.max_tokens,\n            }\n        else:\n            test_payload = None\n    \n        logger.info(f\"Calling LLM service at {model_url} with payload {test_payload}\")\n        try:\n            if test_payload is not None:\n                response = post_with_retry(\n                    model_url,\n                    headers=headers,\n                    json_data=test_payload,\n                    timeout=test_case.response_timeout,\n                )\n            else:\n                response = get_with_retry(\n                    model_url,\n                    headers=headers,\n                    timeout=test_case.response_timeout,\n                )\n        except Exception as e:\n            logger.error(f\"\u274c Failed to call model: {e}\")\n>           raise AssertionError(f\"\u274c Failed to call model: {e}\") from e\nE           AssertionError: \u274c Failed to call model: HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Max retries exceeded with url: /kserve-ci-e2e-test/rolling-upgrade-test/v1/completions (Caused by ReadTimeoutError(\"HTTPConnectionPool(host='ae063886a26074181a63b39cd9058f0e-258571161.us-east-1.elb.amazonaws.com', port=80): Read timed out. (read timeout=60)\"))\n\nllmisvc/test_llm_inference_service.py:1109: AssertionError"}, "teardown": {"duration": 0.0023672819952480495, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_storage_version_migration.py::TestStorageVersionMigration::test_storage_version_migration_after_simulated_upgrade", "lineno": 113, "outcome": "passed", "keywords": ["test_storage_version_migration_after_simulated_upgrade", "cluster_single_node", "cluster_cpu", "pytestmark", "TestStorageVersionMigration", "conversion", "llminferenceservice", "test_storage_version_migration.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.013170391997846309, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 83.23623832099838, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 2.486795228003757, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}], "warnings": [{"message": "The event_loop fixture provided by pytest-asyncio has been redefined in\n/workspace/source/test/e2e/conftest.py:43\nReplacing the event_loop fixture with a custom implementation is deprecated\nand will lead to errors in the future.\nIf you want to request an asyncio event loop with a scope other than function\nscope, use the \"scope\" argument to the asyncio mark when marking the tests.\nIf you want to return different types of event loops, use the event_loop_policy\nfixture.\n", "category": "DeprecationWarning", "when": "runtest", "filename": "/workspace/source/python/kserve/.venv/lib64/python3.11/site-packages/pytest_asyncio/plugin.py", "lineno": 761}, {"message": "The test <Function test_llm_inference_service[router-managed-scheduler-with-precise-prefix-cache-inline-config-workload-llmd-simulator-kvcache]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-llmd-simulator0]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-llmd-simulator1]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-llmd-simulator2]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The event_loop fixture provided by pytest-asyncio has been redefined in\n/workspace/source/test/e2e/conftest.py:43\nReplacing the event_loop fixture with a custom implementation is deprecated\nand will lead to errors in the future.\nIf you want to request an asyncio event loop with a scope other than function\nscope, use the \"scope\" argument to the asyncio mark when marking the tests.\nIf you want to return different types of event loops, use the event_loop_policy\nfixture.\n", "category": "DeprecationWarning", "when": "runtest", "filename": "/workspace/source/python/kserve/.venv/lib64/python3.11/site-packages/pytest_asyncio/plugin.py", "lineno": 761}, {"message": "The test <Function test_llm_inference_service[router-with-gateway-ref-router-with-managed-route-model-fb-opt-125m-workload-llmd-simulator]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf0]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf1]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-custom-route-timeout-scheduler-managed-workload-single-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-with-refs-scheduler-managed-workload-single-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-single-cpu-model-pvc]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-pd-cpu-model-pvc]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-pd-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-simulated-dp-ep-cpu-model-pvc]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-with-refs-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-no-scheduler-workload-single-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_stop_feature[router-managed-workload-single-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service_stop.py", "lineno": 40}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-simulated-dp-ep-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-scheduler-with-inline-config-workload-llmd-simulator]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-workload-llmd-simulator-model-qwen2.5-0.5b]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-scheduler-with-configmap-ref-workload-llmd-simulator]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_tls_resources[router-managed-workload-single-cpu-model-fb-opt-125m]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_tls.py", "lineno": 93}, {"message": "The test <Function test_llm_inference_service[router-managed-scheduler-with-replicas-workload-llmd-simulator]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-scheduler-with-custom-template-workload-llmd-simulator]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-scheduler-v06-pd-config-migration-workload-llmd-simulator-pd]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}, {"message": "The test <Function test_llm_inference_service[router-managed-scheduler-v06-nonzero-threshold-migration-workload-llmd-simulator-pd]> is marked with '@pytest.mark.asyncio' but it is not an async function. Please remove the asyncio mark. If the test is not marked explicitly, check for global marks applied via 'pytestmark'.", "category": "PytestWarning", "when": "runtest", "filename": "llmisvc/test_llm_inference_service.py", "lineno": 245}]}