{"created": 1785259447.3890514, "duration": 5839.893706560135, "exitcode": 2, "root": "/workspace/source/test/e2e", "environment": {}, "summary": {"passed": 51, "failed": 8, "error": 2, "total": 61, "collected": 73}, "collectors": [{"nodeid": "explainer/test_art_explainer.py", "outcome": "skipped", "result": [], "longrepr": "('/workspace/source/test/e2e/explainer/test_art_explainer.py', 48, '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', 39, '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_flow_control.py::test_flow_control_smoke[cluster_cpu-cluster_single_node-flow-control-utilization-detector]", "lineno": 46, "outcome": "passed", "keywords": ["test_flow_control_smoke[flow-control-utilization-detector]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "flow_control", "pytestmark", "flow-control-utilization-detector", "llminferenceservice", "llmisvc_core", "test_flow_control.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.5475053750014922, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 88.65365051000117, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03764037699875189, "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-no-scheduler-workload-single-cpu-model-fb-opt-125m]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-no-scheduler-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "no_scheduler", "__wrapped__", "pytestmark", "router-no-scheduler-workload-single-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.5482454910015804, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 185.8780763199975, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.039257055999769364, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_flow_control.py::test_flow_control_smoke[cluster_cpu-cluster_single_node-flow-control-concurrency-detector]", "lineno": 46, "outcome": "passed", "keywords": ["test_flow_control_smoke[flow-control-concurrency-detector]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "flow_control", "pytestmark", "flow-control-concurrency-detector", "llminferenceservice", "llmisvc_core", "test_flow_control.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.2898382910025248, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 69.2672869420021, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.037950909998471616, "outcome": "passed", "longrepr": "[gw0] 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-with-section-name]", "lineno": 131, "outcome": "passed", "keywords": ["test_gateway_section_name_propagation[with-section-name]", "parametrize", "llmd_simulator", "cluster_single_node", "cluster_cpu", "pytestmark", "with-section-name", "llminferenceservice", "llmisvc_core", "test_gateway_section_name.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.16541770199910388, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 8.083771294001053, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.034301241001230665, "outcome": "passed", "longrepr": "[gw0] 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", "pytestmark", "without-section-name", "llminferenceservice", "llmisvc_core", "test_gateway_section_name.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.15467648899721098, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 31.71983525000178, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.046891486999811605, "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": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-simulated-dp-ep-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "cluster_cpu", "cluster_multi_node", "__wrapped__", "pytestmark", "router-managed-workload-simulated-dp-ep-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.5674075040005846, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 220.8508527949998, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03882852099923184, "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_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", "llmisvc_core", "test_llm_auth.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.5104584170003363, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 187.37402272799955, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.045279747999302344, "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_invalid_token_rejected[cluster_cpu-cluster_single_node-auth-invalid-token]", "lineno": 386, "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", "llmisvc_core", "test_llm_auth.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.35692700800063903, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 146.92742851000003, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03902937699967879, "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-inline-config-workload-llmd-simulator]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-inline-config-workload-llmd-simulator]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-scheduler-with-inline-config-workload-llmd-simulator", "llminferenceservice", "llmisvc_core", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.3096573660004651, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 70.70249958700151, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04631802199946833, "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-simulator-model-qwen2.5-0.5b]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-llmd-simulator-model-qwen2.5-0.5b]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-model-qwen2.5-0.5b", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.3171968860006018, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 61.84553837499698, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03909457199915778, "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": 523, "outcome": "passed", "keywords": ["test_llm_auth_disabled_no_token_required[auth-disabled]", "parametrize", "auth", "llminferenceservice", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "auth-disabled", "llmisvc_core", "test_llm_auth.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.32923032400140073, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 155.9742825359972, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04221363499891595, "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-configmap-ref-workload-llmd-simulator]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-configmap-ref-workload-llmd-simulator]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-scheduler-with-configmap-ref-workload-llmd-simulator", "llminferenceservice", "llmisvc_core", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.9318146779987728, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 71.39097333099926, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.07763285900000483, "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-replicas-workload-llmd-simulator]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-replicas-workload-llmd-simulator]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-scheduler-with-replicas-workload-llmd-simulator", "llminferenceservice", "llmisvc_core", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.3484650199970929, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 62.50017369499983, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.041013833000761224, "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": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-custom-template-workload-llmd-simulator]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-scheduler-with-custom-template-workload-llmd-simulator", "llminferenceservice", "llmisvc_core", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.3558391910009959, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 78.8751756519996, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03981133900015266, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_autoscaling_wva.py::test_llm_autoscaling_hpa_deployment[cluster_cpu-cluster_single_node-router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-hpa]", "lineno": 507, "outcome": "failed", "keywords": ["test_llm_autoscaling_hpa_deployment[router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-hpa]", "parametrize", "autoscaling_hpa", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-hpa", "llminferenceservice", "llmisvc_autoscaling", "autoscaling_wva", "test_llm_autoscaling_wva.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.7725042170022789, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 926.2866241599986, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T15:59:06Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T15:59:06Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T15:59:06Z', 'severity': 'Info', 'status': 'True', 'type': 'MainWorkloadReady'}, {'lastTransitionTime': '2026-07-28T15:58:53Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T15:59:24Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-deployment-9ba6f3f4/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-deploy-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T15:59:24Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T15:59:07Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-deployment-9ba6f3f4/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-deploy-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T15:59:24Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T15:59:07Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-deployment-9ba6f3f4/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-deploy-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'WorkloadsReady'}]"}, "traceback": [{"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 542, "message": ""}, {"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 482, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1376, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1387, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError"}], "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-no-replicas', 'prometheus-scrape', 'scaling-hpa'], prom...              {'name': 'scaling-hpa-autoscale-hpa-deplo-347a3180'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.autoscaling_hpa\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator-no-replicas\",\n                        \"prometheus-scrape\",\n                        \"scaling-hpa\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"autoscale-hpa-deploy\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_autoscaling_hpa_deployment(test_case: TestCase):\n        \"\"\"HPA + Deployment: HPA exists with WVA annotations; pods scale up under load.\"\"\"\n        inject_k8s_proxy()\n        kserve_client = _new_kserve_client()\n        service_name = test_case.llm_service.metadata.name\n        ns = test_case.namespace\n    \n        try:\n>           _create_and_wait(kserve_client, test_case)\n\nllmisvc/test_llm_autoscaling_wva.py:542: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f0dd08a58d0>\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-no-replicas', 'prometheus-scrape', 'scaling-hpa'], prom...              {'name': 'scaling-hpa-autoscale-hpa-deplo-347a3180'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    def _create_and_wait(kserve_client, test_case):\n        \"\"\"Create LLMISVC and wait for it to be ready.\"\"\"\n        create_llmisvc(kserve_client, test_case.llm_service)\n>       wait_for_llm_isvc_ready(\n            kserve_client, test_case.llm_service, test_case.wait_timeout\n        )\n\nllmisvc/test_llm_autoscaling_wva.py:482: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f0dd08a58d0>, {'api_version': 'serving.kserve.io/v1alpha1',\n 'kin...e-hpa-4c186bcf'},\n                       {'name': 'scaling-hpa-autoscale-hpa-deplo-347a3180'}]},\n 'status': None}, 900)\nkwargs = {}, func_name = 'wait_for_llm_isvc_ready'\ntimestamp_start = '2026-07-28T15:58:21.578162', start_time = 1785254301.5784934\nduration = 900.7017710208893, timestamp_end = '2026-07-28T16:13:22.280286'\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 0x7f0dd08a58d0>\ngiven = {'api_version': 'serving.kserve.io/v1alpha1',\n 'kind': 'LLMInferenceService',\n 'metadata': {'annotations': {'security....toscale-hpa-4c186bcf'},\n                       {'name': 'scaling-hpa-autoscale-hpa-deplo-347a3180'}]},\n 'status': None}\ntimeout_seconds = 900\n\n    @log_execution\n    def wait_for_llm_isvc_ready(\n        kserve_client: KServeClient,\n        given: V1alpha1LLMInferenceService,\n        timeout_seconds: int = 900,\n    ) -> str:\n        def assert_llm_isvc_ready():\n            out = get_llmisvc(\n                kserve_client,\n                given.metadata.name,\n                given.metadata.namespace,\n                given.api_version.split(\"/\")[1],\n            )\n    \n            if \"status\" not in out:\n                raise AssertionError(\"No status found in LLM inference service\")\n    \n            status = out[\"status\"]\n            if \"conditions\" not in status:\n                raise AssertionError(\"No conditions found in status\")\n    \n            expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n            got_true_conditions = set()\n            all_condition_types = set()\n    \n            conditions = status[\"conditions\"]\n    \n            for condition in conditions:\n                ctype = condition.get(\"type\")\n                all_condition_types.add(ctype)\n                if condition.get(\"status\") == \"True\":\n                    got_true_conditions.add(ctype)\n    \n            # When TokenizerReady is present, it must also be True\n            if \"TokenizerReady\" in all_condition_types:\n                expected_true_conditions.add(\"TokenizerReady\")\n    \n            missing_conditions = expected_true_conditions - got_true_conditions\n            if missing_conditions:\n                raise AssertionError(\n                    f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n                )\n            return True\n    \n>       return wait_for(assert_llm_isvc_ready, timeout=timeout_seconds, interval=1.0)\n\nllmisvc/test_llm_inference_service.py:1376: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_llm_isvc_ready.<locals>.assert_llm_isvc_ready at 0x7f0dd0031ee0>\ntimeout = 900, interval = 1.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:1387: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def assert_llm_isvc_ready():\n        out = get_llmisvc(\n            kserve_client,\n            given.metadata.name,\n            given.metadata.namespace,\n            given.api_version.split(\"/\")[1],\n        )\n    \n        if \"status\" not in out:\n            raise AssertionError(\"No status found in LLM inference service\")\n    \n        status = out[\"status\"]\n        if \"conditions\" not in status:\n            raise AssertionError(\"No conditions found in status\")\n    \n        expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n        got_true_conditions = set()\n        all_condition_types = set()\n    \n        conditions = status[\"conditions\"]\n    \n        for condition in conditions:\n            ctype = condition.get(\"type\")\n            all_condition_types.add(ctype)\n            if condition.get(\"status\") == \"True\":\n                got_true_conditions.add(ctype)\n    \n        # When TokenizerReady is present, it must also be True\n        if \"TokenizerReady\" in all_condition_types:\n            expected_true_conditions.add(\"TokenizerReady\")\n    \n        missing_conditions = expected_true_conditions - got_true_conditions\n        if missing_conditions:\n>           raise AssertionError(\n                f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n            )\nE           AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T15:59:06Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T15:59:06Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T15:59:06Z', 'severity': 'Info', 'status': 'True', 'type': 'MainWorkloadReady'}, {'lastTransitionTime': '2026-07-28T15:58:53Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T15:59:24Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-deployment-9ba6f3f4/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-deploy-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T15:59:24Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T15:59:07Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-deployment-9ba6f3f4/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-deploy-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T15:59:24Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T15:59:07Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-deployment-9ba6f3f4/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-deploy-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'WorkloadsReady'}]\n\nllmisvc/test_llm_inference_service.py:1371: AssertionError"}, "teardown": {"duration": 0.0017297400008828845, "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": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-v06-pd-config-migration-workload-llmd-simulator-pd]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-scheduler-v06-pd-config-migration-workload-llmd-simulator-pd", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.2917132760012464, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 123.96280513599777, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04115065599762602, "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-v06-nonzero-threshold-migration-workload-llmd-simulator-pd]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-v06-nonzero-threshold-migration-workload-llmd-simulator-pd]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-scheduler-v06-nonzero-threshold-migration-workload-llmd-simulator-pd", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.36690523700235644, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 57.91242059800061, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04562652000095113, "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-tokenizer-kvcache-workload-llmd-simulator-kvcache]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-tokenizer-kvcache-workload-llmd-simulator-kvcache]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-scheduler-with-tokenizer-kvcache-workload-llmd-simulator-kvcache", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.2695762749972346, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 119.91824279700086, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.041806827000982594, "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-precise-prefix-cache-inline-config-workload-llmd-simulator-kvcache]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-scheduler-with-precise-prefix-cache-inline-config-workload-llmd-simulator-kvcache]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-scheduler-with-precise-prefix-cache-inline-config-workload-llmd-simulator-kvcache", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.3151252220013703, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 66.18733165400045, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.049317174998577684, "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-simulator0]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-llmd-simulator0]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator0", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.28701387800174416, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 57.07606471899999, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.040634296001371695, "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": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-llmd-simulator1]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "model_routing", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator1", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.38253422399793635, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 121.65631633399971, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04372723399865208, "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-simulator2]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-llmd-simulator2]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "llmd_simulator", "model_routing", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator2", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.480878076999943, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 121.61176621100094, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.042378056001325604, "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-single-cpu-model-fb-opt-125m-with-lora-hf0]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf0]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "model_routing", "lora", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf0", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.4453939060003904, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 137.56515613399824, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03863770300085889, "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-single-cpu-model-fb-opt-125m-with-lora-hf1]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf1]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "model_routing", "lora", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m-with-lora-hf1", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.30100697899979423, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 120.8150567340017, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0515057769989653, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_autoscaling_wva.py::test_llm_autoscaling_keda_deployment[cluster_cpu-cluster_single_node-router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-keda]", "lineno": 571, "outcome": "failed", "keywords": ["test_llm_autoscaling_keda_deployment[router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-keda]", "parametrize", "autoscaling_keda", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-keda", "llminferenceservice", "llmisvc_autoscaling", "autoscaling_wva", "test_llm_autoscaling_wva.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.3741847220007912, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 920.6985616940001, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T16:14:31Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T16:14:31Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T16:14:31Z', 'severity': 'Info', 'status': 'True', 'type': 'MainWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:14:16Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T16:14:47Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T16:14:47Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T16:14:31Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T16:14:47Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:14:31Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'status': 'False', 'type': 'WorkloadsReady'}]"}, "traceback": [{"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 606, "message": ""}, {"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 482, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1376, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1387, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError"}], "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-no-replicas', 'prometheus-scrape', 'scaling-keda'], pro...              {'name': 'scaling-keda-autoscale-keda-dep-1ac84077'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.autoscaling_keda\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator-no-replicas\",\n                        \"prometheus-scrape\",\n                        \"scaling-keda\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"autoscale-keda-deploy\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_autoscaling_keda_deployment(test_case: TestCase):\n        \"\"\"KEDA + Deployment: ScaledObject exists with WVA annotations; no HPA; pods scale up under load.\"\"\"\n        inject_k8s_proxy()\n        kserve_client = _new_kserve_client()\n        service_name = test_case.llm_service.metadata.name\n        ns = test_case.namespace\n    \n        try:\n>           _create_and_wait(kserve_client, test_case)\n\nllmisvc/test_llm_autoscaling_wva.py:606: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f0dd06593d0>\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-no-replicas', 'prometheus-scrape', 'scaling-keda'], pro...              {'name': 'scaling-keda-autoscale-keda-dep-1ac84077'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    def _create_and_wait(kserve_client, test_case):\n        \"\"\"Create LLMISVC and wait for it to be ready.\"\"\"\n        create_llmisvc(kserve_client, test_case.llm_service)\n>       wait_for_llm_isvc_ready(\n            kserve_client, test_case.llm_service, test_case.wait_timeout\n        )\n\nllmisvc/test_llm_autoscaling_wva.py:482: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f0dd06593d0>, {'api_version': 'serving.kserve.io/v1alpha1',\n 'kin...e-ked-101f2a9d'},\n                       {'name': 'scaling-keda-autoscale-keda-dep-1ac84077'}]},\n 'status': None}, 900)\nkwargs = {}, func_name = 'wait_for_llm_isvc_ready'\ntimestamp_start = '2026-07-28T16:13:48.489941', start_time = 1785255228.4902089\nduration = 900.0904982089996, timestamp_end = '2026-07-28T16:28:48.580711'\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 0x7f0dd06593d0>\ngiven = {'api_version': 'serving.kserve.io/v1alpha1',\n 'kind': 'LLMInferenceService',\n 'metadata': {'annotations': {'security....toscale-ked-101f2a9d'},\n                       {'name': 'scaling-keda-autoscale-keda-dep-1ac84077'}]},\n 'status': None}\ntimeout_seconds = 900\n\n    @log_execution\n    def wait_for_llm_isvc_ready(\n        kserve_client: KServeClient,\n        given: V1alpha1LLMInferenceService,\n        timeout_seconds: int = 900,\n    ) -> str:\n        def assert_llm_isvc_ready():\n            out = get_llmisvc(\n                kserve_client,\n                given.metadata.name,\n                given.metadata.namespace,\n                given.api_version.split(\"/\")[1],\n            )\n    \n            if \"status\" not in out:\n                raise AssertionError(\"No status found in LLM inference service\")\n    \n            status = out[\"status\"]\n            if \"conditions\" not in status:\n                raise AssertionError(\"No conditions found in status\")\n    \n            expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n            got_true_conditions = set()\n            all_condition_types = set()\n    \n            conditions = status[\"conditions\"]\n    \n            for condition in conditions:\n                ctype = condition.get(\"type\")\n                all_condition_types.add(ctype)\n                if condition.get(\"status\") == \"True\":\n                    got_true_conditions.add(ctype)\n    \n            # When TokenizerReady is present, it must also be True\n            if \"TokenizerReady\" in all_condition_types:\n                expected_true_conditions.add(\"TokenizerReady\")\n    \n            missing_conditions = expected_true_conditions - got_true_conditions\n            if missing_conditions:\n                raise AssertionError(\n                    f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n                )\n            return True\n    \n>       return wait_for(assert_llm_isvc_ready, timeout=timeout_seconds, interval=1.0)\n\nllmisvc/test_llm_inference_service.py:1376: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_llm_isvc_ready.<locals>.assert_llm_isvc_ready at 0x7f0dd01f2ac0>\ntimeout = 900, interval = 1.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:1387: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def assert_llm_isvc_ready():\n        out = get_llmisvc(\n            kserve_client,\n            given.metadata.name,\n            given.metadata.namespace,\n            given.api_version.split(\"/\")[1],\n        )\n    \n        if \"status\" not in out:\n            raise AssertionError(\"No status found in LLM inference service\")\n    \n        status = out[\"status\"]\n        if \"conditions\" not in status:\n            raise AssertionError(\"No conditions found in status\")\n    \n        expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n        got_true_conditions = set()\n        all_condition_types = set()\n    \n        conditions = status[\"conditions\"]\n    \n        for condition in conditions:\n            ctype = condition.get(\"type\")\n            all_condition_types.add(ctype)\n            if condition.get(\"status\") == \"True\":\n                got_true_conditions.add(ctype)\n    \n        # When TokenizerReady is present, it must also be True\n        if \"TokenizerReady\" in all_condition_types:\n            expected_true_conditions.add(\"TokenizerReady\")\n    \n        missing_conditions = expected_true_conditions - got_true_conditions\n        if missing_conditions:\n>           raise AssertionError(\n                f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n            )\nE           AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T16:14:31Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T16:14:31Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T16:14:31Z', 'severity': 'Info', 'status': 'True', 'type': 'MainWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:14:16Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T16:14:47Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T16:14:47Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T16:14:31Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T16:14:47Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:14:31Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'status': 'False', 'type': 'WorkloadsReady'}]\n\nllmisvc/test_llm_inference_service.py:1371: AssertionError"}, "teardown": {"duration": 0.001502622999396408, "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": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-single-cpu-model-pvc]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "pvc_storage", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-pvc", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 20.51625410899942, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 169.17412496500037, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04152048900141381, "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-pd-cpu-model-pvc]", "lineno": 242, "outcome": "failed", "keywords": ["test_llm_inference_service[router-managed-workload-pd-cpu-model-pvc]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "pvc_storage", "__wrapped__", "pytestmark", "router-managed-workload-pd-cpu-model-pvc", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 20.556574008001917, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 902.4506520880022, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T16:18:55Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T16:18:55Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T16:20:50Z', 'severity': 'Info', 'status': 'True', 'type': 'MainWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:18:55Z', 'message': 'Deployment does not have minimum availability.', 'reason': 'MinimumReplicasUnavailable', 'severity': 'Info', 'status': 'False', 'type': 'PrefillWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:18:44Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T16:18:55Z', 'message': 'Deployment does not have minimum availability.', 'reason': 'MinimumReplicasUnavailable', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T16:19:35Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T16:19:35Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:18:55Z', 'message': 'Deployment does not have minimum availability.', 'reason': 'MinimumReplicasUnavailable', 'status': 'False', 'type': 'WorkloadsReady'}]"}, "traceback": [{"path": "llmisvc/test_llm_inference_service.py", "lineno": 866, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1376, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1387, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError"}], "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-pd-cpu', 'model-pvc'], prompt='KServe is a', service_name='llmisvc-mod...              {'name': 'model-pvc-llmisvc-model-pvc-rou-49c1f027'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\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-gateway-1\",\n                    before_test=[\n                        lambda tc: create_router_resources(\n                            gateways=[\n                                make_router_gateway(\n                                    \"router-gateway-1\",\n                                    tc.namespace,\n                                ),\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.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-gateway-1\",\n                    before_test=[\n                        lambda tc: create_router_resources(\n                            gateways=[\n                                make_router_gateway(\n                                    \"router-gateway-1\",\n                                    tc.namespace,\n                                ),\n                            ],\n                            routes=[\n                                make_router_main_route(\n                                    \"router-route-1\",\n                                    tc.namespace,\n                                    \"router-gateway-1\",\n                                    \"router-with-refs-test\",\n                                ),\n                                make_router_health_route(\n                                    \"router-route-2\",\n                                    tc.namespace,\n                                    \"router-gateway-1\",\n                                    \"router-with-refs-test\",\n                                ),\n                            ],\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-gateway-2\",\n                    before_test=[\n                        lambda tc: create_router_resources(\n                            gateways=[\n                                make_router_gateway(\n                                    \"router-gateway-2\",\n                                    tc.namespace,\n                                ),\n                            ],\n                            routes=[\n                                make_router_main_route(\n                                    \"router-route-3\",\n                                    tc.namespace,\n                                    \"router-gateway-2\",\n                                    \"router-with-refs-pd-test\",\n                                ),\n                                make_router_health_route(\n                                    \"router-route-4\",\n                                    tc.namespace,\n                                    \"router-gateway-2\",\n                                    \"router-with-refs-pd-test\",\n                                ),\n                            ],\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=[\n                        lambda tc: create_scheduler_configmap(namespace=tc.namespace)\n                    ],\n                    after_test=[\n                        lambda tc: delete_scheduler_configmap(namespace=tc.namespace)\n                    ],\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            # Standalone tokenizer \u2014 clean path: token-producer in inline config\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-tokenizer-kvcache\",\n                        \"workload-llmd-simulator-kvcache\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"tokenizer-clean-path-test\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Standalone tokenizer \u2014 migration path: legacy precise-prefix-cache-scorer\n            # triggers auto-provisioned tokenizer without explicit tokenizer:{} field\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=\"tokenizer-migration-path-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: \"publishers/{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: \"publishers/{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: \"publishers/{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: \"publishers/{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=\"publishers/{namespace}/models/lora-adapter-1\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\n                        \"publishers/{namespace}/models/lora-adapter-1\"\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: \"publishers/{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                        \"publishers/{namespace}/models/facebook/opt-125m\",\n                        \"lora-adapter-1\",\n                        \"publishers/{namespace}/models/lora-adapter-1\",\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: \"publishers/{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=[lambda tc: ensure_pvc_with_model(namespace=tc.namespace)],\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=[lambda tc: ensure_pvc_with_model(namespace=tc.namespace)],\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=[lambda tc: ensure_pvc_with_model(namespace=tc.namespace)],\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        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\nllmisvc/test_llm_inference_service.py:866: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7fc202111d50>, {'api_version': 'serving.kserve.io/v1alpha1',\n 'kin...del-p-9d807ba3'},\n                       {'name': 'model-pvc-llmisvc-model-pvc-rou-49c1f027'}]},\n 'status': None}, 900)\nkwargs = {}, func_name = 'wait_for_llm_isvc_ready'\ntimestamp_start = '2026-07-28T16:18:26.479986', start_time = 1785255506.4802804\nduration = 900.4899139404297, timestamp_end = '2026-07-28T16:33:26.970197'\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 0x7fc202111d50>\ngiven = {'api_version': 'serving.kserve.io/v1alpha1',\n 'kind': 'LLMInferenceService',\n 'metadata': {'annotations': {'security....svc-model-p-9d807ba3'},\n                       {'name': 'model-pvc-llmisvc-model-pvc-rou-49c1f027'}]},\n 'status': None}\ntimeout_seconds = 900\n\n    @log_execution\n    def wait_for_llm_isvc_ready(\n        kserve_client: KServeClient,\n        given: V1alpha1LLMInferenceService,\n        timeout_seconds: int = 900,\n    ) -> str:\n        def assert_llm_isvc_ready():\n            out = get_llmisvc(\n                kserve_client,\n                given.metadata.name,\n                given.metadata.namespace,\n                given.api_version.split(\"/\")[1],\n            )\n    \n            if \"status\" not in out:\n                raise AssertionError(\"No status found in LLM inference service\")\n    \n            status = out[\"status\"]\n            if \"conditions\" not in status:\n                raise AssertionError(\"No conditions found in status\")\n    \n            expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n            got_true_conditions = set()\n            all_condition_types = set()\n    \n            conditions = status[\"conditions\"]\n    \n            for condition in conditions:\n                ctype = condition.get(\"type\")\n                all_condition_types.add(ctype)\n                if condition.get(\"status\") == \"True\":\n                    got_true_conditions.add(ctype)\n    \n            # When TokenizerReady is present, it must also be True\n            if \"TokenizerReady\" in all_condition_types:\n                expected_true_conditions.add(\"TokenizerReady\")\n    \n            missing_conditions = expected_true_conditions - got_true_conditions\n            if missing_conditions:\n                raise AssertionError(\n                    f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n                )\n            return True\n    \n>       return wait_for(assert_llm_isvc_ready, timeout=timeout_seconds, interval=1.0)\n\nllmisvc/test_llm_inference_service.py:1376: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_llm_isvc_ready.<locals>.assert_llm_isvc_ready at 0x7fc2021e1440>\ntimeout = 900, interval = 1.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:1387: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def assert_llm_isvc_ready():\n        out = get_llmisvc(\n            kserve_client,\n            given.metadata.name,\n            given.metadata.namespace,\n            given.api_version.split(\"/\")[1],\n        )\n    \n        if \"status\" not in out:\n            raise AssertionError(\"No status found in LLM inference service\")\n    \n        status = out[\"status\"]\n        if \"conditions\" not in status:\n            raise AssertionError(\"No conditions found in status\")\n    \n        expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n        got_true_conditions = set()\n        all_condition_types = set()\n    \n        conditions = status[\"conditions\"]\n    \n        for condition in conditions:\n            ctype = condition.get(\"type\")\n            all_condition_types.add(ctype)\n            if condition.get(\"status\") == \"True\":\n                got_true_conditions.add(ctype)\n    \n        # When TokenizerReady is present, it must also be True\n        if \"TokenizerReady\" in all_condition_types:\n            expected_true_conditions.add(\"TokenizerReady\")\n    \n        missing_conditions = expected_true_conditions - got_true_conditions\n        if missing_conditions:\n>           raise AssertionError(\n                f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n            )\nE           AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T16:18:55Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T16:18:55Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T16:20:50Z', 'severity': 'Info', 'status': 'True', 'type': 'MainWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:18:55Z', 'message': 'Deployment does not have minimum availability.', 'reason': 'MinimumReplicasUnavailable', 'severity': 'Info', 'status': 'False', 'type': 'PrefillWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:18:44Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T16:18:55Z', 'message': 'Deployment does not have minimum availability.', 'reason': 'MinimumReplicasUnavailable', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T16:19:35Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T16:19:35Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:18:55Z', 'message': 'Deployment does not have minimum availability.', 'reason': 'MinimumReplicasUnavailable', 'status': 'False', 'type': 'WorkloadsReady'}]\n\nllmisvc/test_llm_inference_service.py:1371: AssertionError"}, "teardown": {"duration": 0.0018093970029440243, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_autoscaling_wva.py::test_llm_autoscaling_hpa_lws[cluster_cpu-cluster_multi_node-router-managed-workload-llmd-simulator-lws-prometheus-scrape-scaling-hpa]", "lineno": 635, "outcome": "failed", "keywords": ["test_llm_autoscaling_hpa_lws[router-managed-workload-llmd-simulator-lws-prometheus-scrape-scaling-hpa]", "parametrize", "autoscaling_hpa", "cluster_cpu", "cluster_multi_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-lws-prometheus-scrape-scaling-hpa", "llminferenceservice", "llmisvc_autoscaling", "autoscaling_wva", "test_llm_autoscaling_wva.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 1.4259703069983516, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 926.1776937640025, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T16:29:33Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T16:29:33Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T16:29:18Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T16:29:53Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-lws-d4cbcfd2/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-lws-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T16:29:53Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T16:29:33Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-lws-d4cbcfd2/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-lws-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T16:29:53Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:29:33Z', 'severity': 'Info', 'status': 'True', 'type': 'WorkerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:29:33Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-lws-d4cbcfd2/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-lws-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'WorkloadsReady'}]"}, "traceback": [{"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 670, "message": ""}, {"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 482, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1376, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1387, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError"}], "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-lws', 'prometheus-scrape', 'scaling-hpa'], prompt='KSer...                {'name': 'scaling-hpa-autoscale-hpa-lws-b344a3ff'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.autoscaling_hpa\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator-lws\",\n                        \"prometheus-scrape\",\n                        \"scaling-hpa\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"autoscale-hpa-lws\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_multi_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_autoscaling_hpa_lws(test_case: TestCase):\n        \"\"\"HPA + LWS: HPA exists with WVA annotations; pods scale under load.\"\"\"\n        inject_k8s_proxy()\n        kserve_client = _new_kserve_client()\n        service_name = test_case.llm_service.metadata.name\n        ns = test_case.namespace\n    \n        try:\n>           _create_and_wait(kserve_client, test_case)\n\nllmisvc/test_llm_autoscaling_wva.py:670: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f0dd1488390>\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-lws', 'prometheus-scrape', 'scaling-hpa'], prompt='KSer...                {'name': 'scaling-hpa-autoscale-hpa-lws-b344a3ff'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    def _create_and_wait(kserve_client, test_case):\n        \"\"\"Create LLMISVC and wait for it to be ready.\"\"\"\n        create_llmisvc(kserve_client, test_case.llm_service)\n>       wait_for_llm_isvc_ready(\n            kserve_client, test_case.llm_service, test_case.wait_timeout\n        )\n\nllmisvc/test_llm_autoscaling_wva.py:482: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f0dd1488390>, {'api_version': 'serving.kserve.io/v1alpha1',\n 'kin...ale-hpa-b29acdba'},\n                       {'name': 'scaling-hpa-autoscale-hpa-lws-b344a3ff'}]},\n 'status': None}, 900)\nkwargs = {}, func_name = 'wait_for_llm_isvc_ready'\ntimestamp_start = '2026-07-28T16:29:10.602219', start_time = 1785256150.6025183\nduration = 900.720700263977, timestamp_end = '2026-07-28T16:44:11.323225'\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 0x7f0dd1488390>\ngiven = {'api_version': 'serving.kserve.io/v1alpha1',\n 'kind': 'LLMInferenceService',\n 'metadata': {'annotations': {'security....autoscale-hpa-b29acdba'},\n                       {'name': 'scaling-hpa-autoscale-hpa-lws-b344a3ff'}]},\n 'status': None}\ntimeout_seconds = 900\n\n    @log_execution\n    def wait_for_llm_isvc_ready(\n        kserve_client: KServeClient,\n        given: V1alpha1LLMInferenceService,\n        timeout_seconds: int = 900,\n    ) -> str:\n        def assert_llm_isvc_ready():\n            out = get_llmisvc(\n                kserve_client,\n                given.metadata.name,\n                given.metadata.namespace,\n                given.api_version.split(\"/\")[1],\n            )\n    \n            if \"status\" not in out:\n                raise AssertionError(\"No status found in LLM inference service\")\n    \n            status = out[\"status\"]\n            if \"conditions\" not in status:\n                raise AssertionError(\"No conditions found in status\")\n    \n            expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n            got_true_conditions = set()\n            all_condition_types = set()\n    \n            conditions = status[\"conditions\"]\n    \n            for condition in conditions:\n                ctype = condition.get(\"type\")\n                all_condition_types.add(ctype)\n                if condition.get(\"status\") == \"True\":\n                    got_true_conditions.add(ctype)\n    \n            # When TokenizerReady is present, it must also be True\n            if \"TokenizerReady\" in all_condition_types:\n                expected_true_conditions.add(\"TokenizerReady\")\n    \n            missing_conditions = expected_true_conditions - got_true_conditions\n            if missing_conditions:\n                raise AssertionError(\n                    f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n                )\n            return True\n    \n>       return wait_for(assert_llm_isvc_ready, timeout=timeout_seconds, interval=1.0)\n\nllmisvc/test_llm_inference_service.py:1376: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_llm_isvc_ready.<locals>.assert_llm_isvc_ready at 0x7f0dcb7e2200>\ntimeout = 900, interval = 1.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:1387: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def assert_llm_isvc_ready():\n        out = get_llmisvc(\n            kserve_client,\n            given.metadata.name,\n            given.metadata.namespace,\n            given.api_version.split(\"/\")[1],\n        )\n    \n        if \"status\" not in out:\n            raise AssertionError(\"No status found in LLM inference service\")\n    \n        status = out[\"status\"]\n        if \"conditions\" not in status:\n            raise AssertionError(\"No conditions found in status\")\n    \n        expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n        got_true_conditions = set()\n        all_condition_types = set()\n    \n        conditions = status[\"conditions\"]\n    \n        for condition in conditions:\n            ctype = condition.get(\"type\")\n            all_condition_types.add(ctype)\n            if condition.get(\"status\") == \"True\":\n                got_true_conditions.add(ctype)\n    \n        # When TokenizerReady is present, it must also be True\n        if \"TokenizerReady\" in all_condition_types:\n            expected_true_conditions.add(\"TokenizerReady\")\n    \n        missing_conditions = expected_true_conditions - got_true_conditions\n        if missing_conditions:\n>           raise AssertionError(\n                f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n            )\nE           AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T16:29:33Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T16:29:33Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T16:29:18Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T16:29:53Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-lws-d4cbcfd2/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-lws-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T16:29:53Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T16:29:33Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-lws-d4cbcfd2/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-lws-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T16:29:53Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:29:33Z', 'severity': 'Info', 'status': 'True', 'type': 'WorkerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:29:33Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-hpa-lws-d4cbcfd2/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-hpa-lws-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'WorkloadsReady'}]\n\nllmisvc/test_llm_inference_service.py:1371: AssertionError"}, "teardown": {"duration": 0.002437335002468899, "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-pvc]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-simulated-dp-ep-cpu-model-pvc]", "parametrize", "asyncio", "cluster_cpu", "cluster_multi_node", "pvc_storage", "__wrapped__", "pytestmark", "router-managed-workload-simulated-dp-ep-cpu-model-pvc", "llminferenceservice", "llmisvc_core", "llmd_simulator", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 20.99524438300068, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 173.40588916400156, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.042645584002457326, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_config_deletion.py::test_config_finalizer_added", "lineno": 191, "outcome": "passed", "keywords": ["test_config_finalizer_added", "cluster_single_node", "cluster_cpu", "__wrapped__", "pytestmark", "llminferenceservice", "llmisvc_core", "test_llm_inference_service_config_deletion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.17955924600028084, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 2.2269238459994085, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0371415480003634, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_config_deletion.py::test_config_deletion_blocked_when_referenced", "lineno": 224, "outcome": "passed", "keywords": ["test_config_deletion_blocked_when_referenced", "cluster_single_node", "cluster_cpu", "__wrapped__", "pytestmark", "llminferenceservice", "llmisvc_core", "test_llm_inference_service_config_deletion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.15657109699895955, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 6.703130829002475, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.035638525001559174, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_config_deletion.py::test_config_deletion_allowed_when_unreferenced", "lineno": 314, "outcome": "passed", "keywords": ["test_config_deletion_allowed_when_unreferenced", "cluster_single_node", "cluster_cpu", "__wrapped__", "pytestmark", "llminferenceservice", "llmisvc_core", "test_llm_inference_service_config_deletion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.18762073499965481, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 4.187309914999787, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03433235599732143, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_config_deletion.py::test_config_deletion_unblocked_after_service_deleted", "lineno": 349, "outcome": "passed", "keywords": ["test_config_deletion_unblocked_after_service_deleted", "cluster_single_node", "cluster_cpu", "__wrapped__", "pytestmark", "llminferenceservice", "llmisvc_core", "test_llm_inference_service_config_deletion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1825614379995386, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 4.667265952000889, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03338045399868861, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_config_deletion.py::test_well_known_config_deletion_prevented_by_webhook", "lineno": 431, "outcome": "passed", "keywords": ["test_well_known_config_deletion_prevented_by_webhook", "cluster_single_node", "cluster_cpu", "__wrapped__", "pytestmark", "llminferenceservice", "llmisvc_core", "test_llm_inference_service_config_deletion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.04289981500187423, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.1264376529979927, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.0003373459985596128, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_inference_service_config_deletion.py::test_well_known_config_deletion_blocked_by_implicit_reference", "lineno": 465, "outcome": "passed", "keywords": ["test_well_known_config_deletion_blocked_by_implicit_reference", "cluster_single_node", "cluster_cpu", "__wrapped__", "pytestmark", "llminferenceservice", "llmisvc_core", "test_llm_inference_service_config_deletion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.18298964100176818, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 4.7085233030011295, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03815568600111874, "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_v1alpha1_to_v1alpha2_conversion", "lineno": 211, "outcome": "passed", "keywords": ["test_v1alpha1_to_v1alpha2_conversion", "cluster_single_node", "cluster_cpu", "pytestmark", "llminferenceservice", "TestLLMInferenceServiceConversion", "conversion", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.18390313000054448, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.2896116849988175, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.2211514270020416, "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": 302, "outcome": "passed", "keywords": ["test_v1alpha2_to_v1alpha1_conversion", "cluster_single_node", "cluster_cpu", "pytestmark", "llminferenceservice", "TestLLMInferenceServiceConversion", "conversion", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.16770945399912307, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.20551035400058026, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.06423008799902163, "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": 393, "outcome": "passed", "keywords": ["test_criticality_preservation_via_annotations", "cluster_single_node", "cluster_cpu", "pytestmark", "llminferenceservice", "TestLLMInferenceServiceConversion", "conversion", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.18797339700176963, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.4331514320001588, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.16018694599915762, "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": 530, "outcome": "passed", "keywords": ["test_lora_criticality_preservation", "cluster_single_node", "cluster_cpu", "pytestmark", "llminferenceservice", "TestLLMInferenceServiceConversion", "conversion", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1651855140007683, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.6725098050010274, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.3396470389998285, "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": 679, "outcome": "passed", "keywords": ["test_round_trip_conversion_preserves_fields", "cluster_single_node", "cluster_cpu", "pytestmark", "llminferenceservice", "TestLLMInferenceServiceConversion", "conversion", "test_llm_inference_service_conversion.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.16820288200324285, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 0.990980638001929, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.245033915998647, "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", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "test_llm_inference_service_stop.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.6932185619989468, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 315.90551000300184, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03532186300071771, "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-single-lora-adapter-hf]", "lineno": 209, "outcome": "passed", "keywords": ["test_llm_with_lora_adapters[single-lora-adapter-hf]", "parametrize", "cluster_cpu", "lora", "__wrapped__", "pytestmark", "single-lora-adapter-hf", "llminferenceservice", "llmisvc_core", "test_llm_lora_adapters.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.16210830499767326, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 205.16434071600088, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04062238299957244, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_autoscaling_wva.py::test_llm_autoscaling_keda_lws[cluster_cpu-cluster_multi_node-router-managed-workload-llmd-simulator-lws-prometheus-scrape-scaling-keda]", "lineno": 693, "outcome": "failed", "keywords": ["test_llm_autoscaling_keda_lws[router-managed-workload-llmd-simulator-lws-prometheus-scrape-scaling-keda]", "parametrize", "autoscaling_keda", "cluster_cpu", "cluster_multi_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-lws-prometheus-scrape-scaling-keda", "llminferenceservice", "llmisvc_autoscaling", "autoscaling_wva", "test_llm_autoscaling_wva.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 1.0812107320016366, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 931.7474920139975, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T16:45:48Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T16:45:02Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'severity': 'Info', 'status': 'True', 'type': 'WorkerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'status': 'False', 'type': 'WorkloadsReady'}]"}, "traceback": [{"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 728, "message": ""}, {"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 482, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1376, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1387, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError"}], "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-lws', 'prometheus-scrape', 'scaling-keda'], prompt='KSe...              {'name': 'scaling-keda-autoscale-keda-lws-1337f511'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.autoscaling_keda\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator-lws\",\n                        \"prometheus-scrape\",\n                        \"scaling-keda\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"autoscale-keda-lws\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_multi_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_autoscaling_keda_lws(test_case: TestCase):\n        \"\"\"KEDA + LWS: ScaledObject exists with WVA annotations; pods scale under load.\"\"\"\n        inject_k8s_proxy()\n        kserve_client = _new_kserve_client()\n        service_name = test_case.llm_service.metadata.name\n        ns = test_case.namespace\n    \n        try:\n>           _create_and_wait(kserve_client, test_case)\n\nllmisvc/test_llm_autoscaling_wva.py:728: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f0dd07ca190>\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-lws', 'prometheus-scrape', 'scaling-keda'], prompt='KSe...              {'name': 'scaling-keda-autoscale-keda-lws-1337f511'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    def _create_and_wait(kserve_client, test_case):\n        \"\"\"Create LLMISVC and wait for it to be ready.\"\"\"\n        create_llmisvc(kserve_client, test_case.llm_service)\n>       wait_for_llm_isvc_ready(\n            kserve_client, test_case.llm_service, test_case.wait_timeout\n        )\n\nllmisvc/test_llm_autoscaling_wva.py:482: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f0dd07ca190>, {'api_version': 'serving.kserve.io/v1alpha1',\n 'kin...e-ked-231d315d'},\n                       {'name': 'scaling-keda-autoscale-keda-lws-1337f511'}]},\n 'status': None}, 900)\nkwargs = {}, func_name = 'wait_for_llm_isvc_ready'\ntimestamp_start = '2026-07-28T16:44:38.171452', start_time = 1785257078.1717303\nduration = 900.9549708366394, timestamp_end = '2026-07-28T16:59:39.126704'\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 0x7f0dd07ca190>\ngiven = {'api_version': 'serving.kserve.io/v1alpha1',\n 'kind': 'LLMInferenceService',\n 'metadata': {'annotations': {'security....toscale-ked-231d315d'},\n                       {'name': 'scaling-keda-autoscale-keda-lws-1337f511'}]},\n 'status': None}\ntimeout_seconds = 900\n\n    @log_execution\n    def wait_for_llm_isvc_ready(\n        kserve_client: KServeClient,\n        given: V1alpha1LLMInferenceService,\n        timeout_seconds: int = 900,\n    ) -> str:\n        def assert_llm_isvc_ready():\n            out = get_llmisvc(\n                kserve_client,\n                given.metadata.name,\n                given.metadata.namespace,\n                given.api_version.split(\"/\")[1],\n            )\n    \n            if \"status\" not in out:\n                raise AssertionError(\"No status found in LLM inference service\")\n    \n            status = out[\"status\"]\n            if \"conditions\" not in status:\n                raise AssertionError(\"No conditions found in status\")\n    \n            expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n            got_true_conditions = set()\n            all_condition_types = set()\n    \n            conditions = status[\"conditions\"]\n    \n            for condition in conditions:\n                ctype = condition.get(\"type\")\n                all_condition_types.add(ctype)\n                if condition.get(\"status\") == \"True\":\n                    got_true_conditions.add(ctype)\n    \n            # When TokenizerReady is present, it must also be True\n            if \"TokenizerReady\" in all_condition_types:\n                expected_true_conditions.add(\"TokenizerReady\")\n    \n            missing_conditions = expected_true_conditions - got_true_conditions\n            if missing_conditions:\n                raise AssertionError(\n                    f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n                )\n            return True\n    \n>       return wait_for(assert_llm_isvc_ready, timeout=timeout_seconds, interval=1.0)\n\nllmisvc/test_llm_inference_service.py:1376: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_llm_isvc_ready.<locals>.assert_llm_isvc_ready at 0x7f0dcb7e2340>\ntimeout = 900, interval = 1.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:1387: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def assert_llm_isvc_ready():\n        out = get_llmisvc(\n            kserve_client,\n            given.metadata.name,\n            given.metadata.namespace,\n            given.api_version.split(\"/\")[1],\n        )\n    \n        if \"status\" not in out:\n            raise AssertionError(\"No status found in LLM inference service\")\n    \n        status = out[\"status\"]\n        if \"conditions\" not in status:\n            raise AssertionError(\"No conditions found in status\")\n    \n        expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n        got_true_conditions = set()\n        all_condition_types = set()\n    \n        conditions = status[\"conditions\"]\n    \n        for condition in conditions:\n            ctype = condition.get(\"type\")\n            all_condition_types.add(ctype)\n            if condition.get(\"status\") == \"True\":\n                got_true_conditions.add(ctype)\n    \n        # When TokenizerReady is present, it must also be True\n        if \"TokenizerReady\" in all_condition_types:\n            expected_true_conditions.add(\"TokenizerReady\")\n    \n        missing_conditions = expected_true_conditions - got_true_conditions\n        if missing_conditions:\n>           raise AssertionError(\n                f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n            )\nE           AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T16:45:48Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T16:45:02Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'severity': 'Info', 'status': 'True', 'type': 'WorkerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T16:45:48Z', 'message': 'failed to ensure HPA is correctly created for ScaledObject: error parsing prometheus metadata: error parsing prometheus metadata: bearer token=<empty> is required when bearer auth is enabled', 'reason': 'ScaledObjectCheckFailed', 'status': 'False', 'type': 'WorkloadsReady'}]\n\nllmisvc/test_llm_inference_service.py:1371: AssertionError"}, "teardown": {"duration": 0.0018079859983117785, "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-multiple-lora-adapters]", "lineno": 209, "outcome": "passed", "keywords": ["test_llm_with_lora_adapters[multiple-lora-adapters]", "parametrize", "cluster_cpu", "lora", "__wrapped__", "pytestmark", "multiple-lora-adapters", "llminferenceservice", "llmisvc_core", "test_llm_lora_adapters.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.18145484599881456, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 183.49473340900295, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.039156992999778595, "outcome": "passed", "longrepr": "[gw1] 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": 91, "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", "llmisvc_core", "test_llm_tls.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.6672452680031711, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 188.09281478100092, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04230281399941305, "outcome": "passed", "longrepr": "[gw1] 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", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "test_prestop_hook.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.4875136629998451, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 229.15534182199917, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.042205670000839746, "outcome": "passed", "longrepr": "[gw1] 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": "passed", "keywords": ["test_rolling_upgrade_coordination[router-managed-workload-llmd-simulator-model-fb-opt-125m]", "parametrize", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "llmd_simulator", "test_rolling_upgrade.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.6797134929984168, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 90.5759166300013, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03267470300124842, "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": 112, "outcome": "passed", "keywords": ["test_storage_version_migration_after_simulated_upgrade", "cluster_single_node", "cluster_cpu", "pytestmark", "llminferenceservice", "TestStorageVersionMigration", "conversion", "test_storage_version_migration.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.16335586700006388, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 78.02279238600022, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 2.1045777119979903, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_canary_lifecycle.py::TestCanaryLifecycle::test_leave_group", "lineno": 992, "outcome": "passed", "keywords": ["test_leave_group", "llminferenceservice", "llmisvc_core", "TestCanaryLifecycle", "cluster_cpu", "traffic", "test_llm_canary_lifecycle.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.16981517499880283, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 193.92733832399972, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.050846503996581305, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_autoscaling_wva.py::test_llm_autoscaling_cleanup_hpa[cluster_cpu-cluster_single_node-router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-hpa]", "lineno": 857, "outcome": "failed", "keywords": ["test_llm_autoscaling_cleanup_hpa[router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-hpa]", "parametrize", "autoscaling_hpa", "cluster_cpu", "cluster_single_node", "llmd_simulator", "__wrapped__", "pytestmark", "router-managed-workload-llmd-simulator-no-replicas-prometheus-scrape-scaling-hpa", "llminferenceservice", "llmisvc_autoscaling", "autoscaling_wva", "test_llm_autoscaling_wva.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.9500720509968232, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 926.3760408960006, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T17:01:12Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T17:01:12Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T17:01:12Z', 'severity': 'Info', 'status': 'True', 'type': 'MainWorkloadReady'}, {'lastTransitionTime': '2026-07-28T17:00:47Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T17:01:39Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-cleanup-hpa-a41f0e40/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-cleanup-hpa-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T17:01:39Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T17:01:12Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-cleanup-hpa-a41f0e40/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-cleanup-hpa-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T17:01:39Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T17:01:12Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-cleanup-hpa-a41f0e40/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-cleanup-hpa-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'WorkloadsReady'}]"}, "traceback": [{"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 892, "message": ""}, {"path": "llmisvc/test_llm_autoscaling_wva.py", "lineno": 482, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1376, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1387, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1371, "message": "AssertionError"}], "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-no-replicas', 'prometheus-scrape', 'scaling-hpa'], prom...              {'name': 'scaling-hpa-autoscale-cleanup-h-aa1ae037'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    @pytest.mark.autoscaling_hpa\n    @pytest.mark.parametrize(\n        \"test_case\",\n        [\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"workload-llmd-simulator-no-replicas\",\n                        \"prometheus-scrape\",\n                        \"scaling-hpa\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"autoscale-cleanup-hpa\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n        ],\n        indirect=[\"test_case\"],\n        ids=generate_test_id,\n    )\n    @log_execution\n    def test_llm_autoscaling_cleanup_hpa(test_case: TestCase):\n        \"\"\"Removing scaling config should delete HPA.\"\"\"\n        inject_k8s_proxy()\n        kserve_client = _new_kserve_client()\n        service_name = test_case.llm_service.metadata.name\n        ns = test_case.namespace\n    \n        try:\n>           _create_and_wait(kserve_client, test_case)\n\nllmisvc/test_llm_autoscaling_wva.py:892: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7f0dd146f1d0>\ntest_case = TestCase(base_refs=['router-managed', 'workload-llmd-simulator-no-replicas', 'prometheus-scrape', 'scaling-hpa'], prom...              {'name': 'scaling-hpa-autoscale-cleanup-h-aa1ae037'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\n    def _create_and_wait(kserve_client, test_case):\n        \"\"\"Create LLMISVC and wait for it to be ready.\"\"\"\n        create_llmisvc(kserve_client, test_case.llm_service)\n>       wait_for_llm_isvc_ready(\n            kserve_client, test_case.llm_service, test_case.wait_timeout\n        )\n\nllmisvc/test_llm_autoscaling_wva.py:482: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7f0dd146f1d0>, {'api_version': 'serving.kserve.io/v1alpha1',\n 'kin...e-cle-5a67f5d1'},\n                       {'name': 'scaling-hpa-autoscale-cleanup-h-aa1ae037'}]},\n 'status': None}, 900)\nkwargs = {}, func_name = 'wait_for_llm_isvc_ready'\ntimestamp_start = '2026-07-28T17:00:10.807570', start_time = 1785258010.8078423\nduration = 900.6285457611084, timestamp_end = '2026-07-28T17:15:11.436391'\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 0x7f0dd146f1d0>\ngiven = {'api_version': 'serving.kserve.io/v1alpha1',\n 'kind': 'LLMInferenceService',\n 'metadata': {'annotations': {'security....toscale-cle-5a67f5d1'},\n                       {'name': 'scaling-hpa-autoscale-cleanup-h-aa1ae037'}]},\n 'status': None}\ntimeout_seconds = 900\n\n    @log_execution\n    def wait_for_llm_isvc_ready(\n        kserve_client: KServeClient,\n        given: V1alpha1LLMInferenceService,\n        timeout_seconds: int = 900,\n    ) -> str:\n        def assert_llm_isvc_ready():\n            out = get_llmisvc(\n                kserve_client,\n                given.metadata.name,\n                given.metadata.namespace,\n                given.api_version.split(\"/\")[1],\n            )\n    \n            if \"status\" not in out:\n                raise AssertionError(\"No status found in LLM inference service\")\n    \n            status = out[\"status\"]\n            if \"conditions\" not in status:\n                raise AssertionError(\"No conditions found in status\")\n    \n            expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n            got_true_conditions = set()\n            all_condition_types = set()\n    \n            conditions = status[\"conditions\"]\n    \n            for condition in conditions:\n                ctype = condition.get(\"type\")\n                all_condition_types.add(ctype)\n                if condition.get(\"status\") == \"True\":\n                    got_true_conditions.add(ctype)\n    \n            # When TokenizerReady is present, it must also be True\n            if \"TokenizerReady\" in all_condition_types:\n                expected_true_conditions.add(\"TokenizerReady\")\n    \n            missing_conditions = expected_true_conditions - got_true_conditions\n            if missing_conditions:\n                raise AssertionError(\n                    f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n                )\n            return True\n    \n>       return wait_for(assert_llm_isvc_ready, timeout=timeout_seconds, interval=1.0)\n\nllmisvc/test_llm_inference_service.py:1376: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_llm_isvc_ready.<locals>.assert_llm_isvc_ready at 0x7f0dcb7e2de0>\ntimeout = 900, interval = 1.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:1387: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def assert_llm_isvc_ready():\n        out = get_llmisvc(\n            kserve_client,\n            given.metadata.name,\n            given.metadata.namespace,\n            given.api_version.split(\"/\")[1],\n        )\n    \n        if \"status\" not in out:\n            raise AssertionError(\"No status found in LLM inference service\")\n    \n        status = out[\"status\"]\n        if \"conditions\" not in status:\n            raise AssertionError(\"No conditions found in status\")\n    \n        expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n        got_true_conditions = set()\n        all_condition_types = set()\n    \n        conditions = status[\"conditions\"]\n    \n        for condition in conditions:\n            ctype = condition.get(\"type\")\n            all_condition_types.add(ctype)\n            if condition.get(\"status\") == \"True\":\n                got_true_conditions.add(ctype)\n    \n        # When TokenizerReady is present, it must also be True\n        if \"TokenizerReady\" in all_condition_types:\n            expected_true_conditions.add(\"TokenizerReady\")\n    \n        missing_conditions = expected_true_conditions - got_true_conditions\n        if missing_conditions:\n>           raise AssertionError(\n                f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n            )\nE           AssertionError: Missing true conditions: {'WorkloadsReady', 'Ready'}, expected {'RouterReady', 'WorkloadsReady', 'Ready'}, got [{'lastTransitionTime': '2026-07-28T17:01:12Z', 'severity': 'Info', 'status': 'True', 'type': 'HTTPRoutesReady'}, {'lastTransitionTime': '2026-07-28T17:01:12Z', 'severity': 'Info', 'status': 'True', 'type': 'InferencePoolReady'}, {'lastTransitionTime': '2026-07-28T17:01:12Z', 'severity': 'Info', 'status': 'True', 'type': 'MainWorkloadReady'}, {'lastTransitionTime': '2026-07-28T17:00:47Z', 'severity': 'Info', 'status': 'True', 'type': 'PresetsCombined'}, {'lastTransitionTime': '2026-07-28T17:01:39Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-cleanup-hpa-a41f0e40/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-cleanup-hpa-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'Ready'}, {'lastTransitionTime': '2026-07-28T17:01:39Z', 'status': 'True', 'type': 'RouterReady'}, {'lastTransitionTime': '2026-07-28T17:01:12Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-cleanup-hpa-a41f0e40/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-cleanup-hpa-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'severity': 'Info', 'status': 'False', 'type': 'ScalingReady'}, {'lastTransitionTime': '2026-07-28T17:01:39Z', 'severity': 'Info', 'status': 'True', 'type': 'SchedulerWorkloadReady'}, {'lastTransitionTime': '2026-07-28T17:01:12Z', 'message': 'the HPA was unable to compute the replica count: unable to get external metric e2e-test-llm-autoscaling-cleanup-hpa-a41f0e40/wva_desired_replicas/&LabelSelector{MatchLabels:map[string]string{variant_name: autoscale-cleanup-hpa-kserve-hpa,},MatchExpressions:[]LabelSelectorRequirement{},}: unable to fetch metrics from external metrics API: scaledObject name is not specified', 'reason': 'FailedGetExternalMetric', 'status': 'False', 'type': 'WorkloadsReady'}]\n\nllmisvc/test_llm_inference_service.py:1371: AssertionError"}, "teardown": {"duration": 0.001600390998646617, "outcome": "passed", "longrepr": "[gw0] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_canary_lifecycle.py::TestCanaryLifecycle::test_three_member_group", "lineno": 1038, "outcome": "passed", "keywords": ["test_three_member_group", "llminferenceservice", "llmisvc_core", "TestCanaryLifecycle", "cluster_cpu", "traffic", "test_llm_canary_lifecycle.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.20762775599723682, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 173.3588087240023, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04112229999736883, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_canary_lifecycle.py::TestCanaryLifecycle::test_late_join", "lineno": 1089, "outcome": "passed", "keywords": ["test_late_join", "llminferenceservice", "llmisvc_core", "TestCanaryLifecycle", "cluster_cpu", "traffic", "test_llm_canary_lifecycle.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1857638740002585, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 184.9121138449991, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.039555667997774435, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_canary_lifecycle.py::TestCanaryLifecycle::test_delete_at_nonzero_weight", "lineno": 1141, "outcome": "passed", "keywords": ["test_delete_at_nonzero_weight", "llminferenceservice", "llmisvc_core", "TestCanaryLifecycle", "cluster_cpu", "traffic", "test_llm_canary_lifecycle.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1585666669998318, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 119.03825202100052, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04024826800014125, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_canary_lifecycle.py::TestCanaryLifecycle::test_rollback", "lineno": 1183, "outcome": "failed", "keywords": ["test_rollback", "llminferenceservice", "llmisvc_core", "TestCanaryLifecycle", "cluster_cpu", "traffic", "test_llm_canary_lifecycle.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1904946939976071, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 116.42023967700152, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_canary_lifecycle.py", "lineno": 566, "message": "TimeoutError: roll-v1 weight=None, expected 0 (from roll-v2)"}, "traceback": [{"path": "llmisvc/test_llm_canary_lifecycle.py", "lineno": 1216, "message": ""}, {"path": "llmisvc/test_llm_canary_lifecycle.py", "lineno": 566, "message": "TimeoutError"}], "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nself = <e2e.llmisvc.test_llm_canary_lifecycle.TestCanaryLifecycle object at 0x7fc2026dfdd0>\ntest_namespace = 'e2e-test-rollback-b8fdb441'\ntraffic_driver = <function traffic_driver.<locals>.factory at 0x7fc201e4b100>\n\n    def test_rollback(self, test_namespace, traffic_driver):\n        \"\"\"Promote v2 then rollback to v1 - traffic returns. (spike step 7)\"\"\"\n        api = get_api()\n        ns = test_namespace\n    \n        v1 = MemberSpec(name=\"roll-v1\", weight=9, scheduler=False)\n        v2 = MemberSpec(name=\"roll-v2\", weight=1, scheduler=False)\n    \n        apply_config(api, INFERENCE_SIM.name, ns, INFERENCE_SIM.to_spec())\n        apply_member(api, v1, ns)\n        apply_member(api, v2, ns)\n    \n        wait_ready(api, v1.name, ns)\n        wait_ready(api, v2.name, ns)\n    \n        gateway = get_gateway_base_url(api, v1.name, ns)\n        driver = traffic_driver(\n            url=f\"{gateway}/v1/completions\",\n            headers={\"X-Gateway-Model-Name\": f\"publishers/{ns}/models/{MODEL}\"},\n            payload={\"model\": MODEL, \"prompt\": \"Hello\", \"max_tokens\": 5},\n            rate=2,\n            timeout=15.0,\n            warmup=True,\n        )\n    \n        route_headers = {\"X-Gateway-Model-Name\": f\"publishers/{ns}/models/{MODEL}\"}\n        route_payload = {\"model\": MODEL, \"prompt\": \"Hello\", \"max_tokens\": 5}\n    \n        # Promote v2\n        driver.mark(\"promote_mutation\")\n        patch_weight(api, v1.name, 0, ns)\n        patch_weight(api, v2.name, 9, ns)\n>       wait_for_group_weight(api, v2.name, v1.name, 0, ns)\n\nllmisvc/test_llm_canary_lifecycle.py:1216: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\napi = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc200e96e90>\nobserver = 'roll-v2', member = 'roll-v1', expected = 0\nns = 'e2e-test-rollback-b8fdb441', timeout = 30\n\n    def wait_for_group_weight(api, observer, member, expected, ns, timeout=30):\n        deadline = time.monotonic() + timeout\n        w = None\n        while time.monotonic() < deadline:\n            w = get_group_weight(api, observer, member, ns)\n            if w == expected:\n                return\n            time.sleep(1)\n>       raise TimeoutError(f\"{member} weight={w}, expected {expected} (from {observer})\")\nE       TimeoutError: roll-v1 weight=None, expected 0 (from roll-v2)\n\nllmisvc/test_llm_canary_lifecycle.py:566: TimeoutError"}, "teardown": {"duration": 0.0008724159997655079, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}}, {"nodeid": "llmisvc/test_llm_canary_lifecycle.py::TestCanaryLifecycle::test_force_stop_route_owner", "lineno": 1254, "outcome": "passed", "keywords": ["test_force_stop_route_owner", "llminferenceservice", "llmisvc_core", "TestCanaryLifecycle", "cluster_cpu", "traffic", "test_llm_canary_lifecycle.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.2826320139974996, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 105.89198141299858, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.03606771900012973, "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": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-with-gateway-ref-router-with-managed-route-model-fb-opt-125m-workload-llmd-simulator]", "parametrize", "asyncio", "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", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 2.644489866997901, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 123.22059396700206, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.02692318000117666, "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-single-cpu-model-fb-opt-125m]", "lineno": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-single-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 1.1468968919980398, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 200.52251632499974, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.04130057600195869, "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": 242, "outcome": "passed", "keywords": ["test_llm_inference_service[router-custom-route-timeout-scheduler-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-custom-route-timeout-scheduler-managed-workload-single-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 1.141496667998581, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 187.48788167600287, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "teardown": {"duration": 0.041422667000006186, "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": 242, "outcome": "failed", "keywords": ["test_llm_inference_service[router-with-refs-scheduler-managed-workload-single-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "custom_gateway", "__wrapped__", "pytestmark", "router-with-refs-scheduler-managed-workload-single-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 2.961365849001595, "outcome": "passed", "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python"}, "call": {"duration": 104.74144432800313, "outcome": "failed", "crash": {"path": "/workspace/source/test/e2e/llmisvc/test_llm_inference_service.py", "lineno": 1212, "message": "RuntimeError: \u274c Exception when calling CustomObjectsApi->get_namespaced_custom_object for LLMInferenceService: (500)\nReason: Internal Server Error\nHTTP response headers: HTTPHeaderDict({'Audit-Id': '8d52e004-35ea-4781-b7af-47e2b20be695', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:04 GMT', 'Content-Length': '264'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"conversion webhook for serving.kserve.io/v1alpha2, Kind=LLMInferenceService failed: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/convert?timeout=30s\\\": EOF\",\"code\":500}"}, "traceback": [{"path": "llmisvc/test_llm_inference_service.py", "lineno": 866, "message": ""}, {"path": "llmisvc/logging.py", "lineno": 40, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1376, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1387, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1339, "message": ""}, {"path": "llmisvc/test_llm_inference_service.py", "lineno": 1212, "message": "RuntimeError"}], "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7fc201cf8f50>\nname = 'router-with-refs-test'\nnamespace = 'e2e-test-llm-inference-service-028f7809', version = 'v1alpha1'\n\n    def get_llmisvc(\n        kserve_client: KServeClient,\n        name,\n        namespace,\n        version=constants.KSERVE_V1ALPHA1_VERSION,\n    ):\n        try:\n>           return kserve_client.api_instance.get_namespaced_custom_object(\n                constants.KSERVE_GROUP,\n                version,\n                namespace,\n                KSERVE_PLURAL_LLMINFERENCESERVICE,\n                name,\n            )\n\nllmisvc/test_llm_inference_service.py:1204: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc201e1f210>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-028f7809'\nplural = 'llminferenceservices', name = 'router-with-refs-test'\nkwargs = {'_return_http_data_only': True}\n\n    def get_namespaced_custom_object(self, group, version, namespace, plural, name, **kwargs):  # noqa: E501\n        \"\"\"get_namespaced_custom_object  # noqa: E501\n    \n        Returns a namespace scoped custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.get_namespaced_custom_object(group, version, namespace, plural, name, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: the custom resource's group (required)\n        :param str version: the custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: the custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param str name: the custom object's name (required)\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: object\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n        kwargs['_return_http_data_only'] = True\n>       return self.get_namespaced_custom_object_with_http_info(group, version, namespace, plural, name, **kwargs)  # noqa: E501\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:1632: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc201e1f210>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-028f7809'\nplural = 'llminferenceservices', name = 'router-with-refs-test'\nkwargs = {'_return_http_data_only': True}\nlocal_var_params = {'_return_http_data_only': True, 'all_params': ['group', 'version', 'namespace', 'plural', 'name', 'async_req', ...], 'auth_settings': ['BearerToken'], 'body_params': None, ...}\nall_params = ['group', 'version', 'namespace', 'plural', 'name', 'async_req', ...]\nkey = '_return_http_data_only', val = True, collection_formats = {}\npath_params = {'group': 'serving.kserve.io', 'name': 'router-with-refs-test', 'namespace': 'e2e-test-llm-inference-service-028f7809', 'plural': 'llminferenceservices', ...}\nquery_params = []\n\n    def get_namespaced_custom_object_with_http_info(self, group, version, namespace, plural, name, **kwargs):  # noqa: E501\n        \"\"\"get_namespaced_custom_object  # noqa: E501\n    \n        Returns a namespace scoped custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.get_namespaced_custom_object_with_http_info(group, version, namespace, plural, name, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: the custom resource's group (required)\n        :param str version: the custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: the custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param str name: the custom object's name (required)\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: tuple(object, status_code(int), headers(HTTPHeaderDict))\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n    \n        local_var_params = locals()\n    \n        all_params = [\n            'group',\n            'version',\n            'namespace',\n            'plural',\n            'name'\n        ]\n        all_params.extend(\n            [\n                'async_req',\n                '_return_http_data_only',\n                '_preload_content',\n                '_request_timeout'\n            ]\n        )\n    \n        for key, val in six.iteritems(local_var_params['kwargs']):\n            if key not in all_params:\n                raise ApiTypeError(\n                    \"Got an unexpected keyword argument '%s'\"\n                    \" to method get_namespaced_custom_object\" % key\n                )\n            local_var_params[key] = val\n        del local_var_params['kwargs']\n        # verify the required parameter 'group' is set\n        if self.api_client.client_side_validation and ('group' not in local_var_params or  # noqa: E501\n                                                        local_var_params['group'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `group` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'version' is set\n        if self.api_client.client_side_validation and ('version' not in local_var_params or  # noqa: E501\n                                                        local_var_params['version'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `version` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'namespace' is set\n        if self.api_client.client_side_validation and ('namespace' not in local_var_params or  # noqa: E501\n                                                        local_var_params['namespace'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `namespace` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'plural' is set\n        if self.api_client.client_side_validation and ('plural' not in local_var_params or  # noqa: E501\n                                                        local_var_params['plural'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `plural` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'name' is set\n        if self.api_client.client_side_validation and ('name' not in local_var_params or  # noqa: E501\n                                                        local_var_params['name'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `name` when calling `get_namespaced_custom_object`\")  # noqa: E501\n    \n        collection_formats = {}\n    \n        path_params = {}\n        if 'group' in local_var_params:\n            path_params['group'] = local_var_params['group']  # noqa: E501\n        if 'version' in local_var_params:\n            path_params['version'] = local_var_params['version']  # noqa: E501\n        if 'namespace' in local_var_params:\n            path_params['namespace'] = local_var_params['namespace']  # noqa: E501\n        if 'plural' in local_var_params:\n            path_params['plural'] = local_var_params['plural']  # noqa: E501\n        if 'name' in local_var_params:\n            path_params['name'] = local_var_params['name']  # noqa: E501\n    \n        query_params = []\n    \n        header_params = {}\n    \n        form_params = []\n        local_var_files = {}\n    \n        body_params = None\n        # HTTP header `Accept`\n        header_params['Accept'] = self.api_client.select_header_accept(\n            ['application/json'])  # noqa: E501\n    \n        # Authentication setting\n        auth_settings = ['BearerToken']  # noqa: E501\n    \n>       return self.api_client.call_api(\n            '/apis/{group}/{version}/namespaces/{namespace}/{plural}/{name}', 'GET',\n            path_params,\n            query_params,\n            header_params,\n            body=body_params,\n            post_params=form_params,\n            files=local_var_files,\n            response_type='object',  # noqa: E501\n            auth_settings=auth_settings,\n            async_req=local_var_params.get('async_req'),\n            _return_http_data_only=local_var_params.get('_return_http_data_only'),  # noqa: E501\n            _preload_content=local_var_params.get('_preload_content', True),\n            _request_timeout=local_var_params.get('_request_timeout'),\n            collection_formats=collection_formats)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:1739: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc201e1d750>\nresource_path = '/apis/{group}/{version}/namespaces/{namespace}/{plural}/{name}'\nmethod = 'GET'\npath_params = {'group': 'serving.kserve.io', 'name': 'router-with-refs-test', 'namespace': 'e2e-test-llm-inference-service-028f7809', 'plural': 'llminferenceservices', ...}\nquery_params = []\nheader_params = {'Accept': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], async_req = None, _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def call_api(self, resource_path, method,\n                 path_params=None, query_params=None, header_params=None,\n                 body=None, post_params=None, files=None,\n                 response_type=None, auth_settings=None, async_req=None,\n                 _return_http_data_only=None, collection_formats=None,\n                 _preload_content=True, _request_timeout=None, _host=None):\n        \"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\n    \n        To make an async_req request, set the async_req parameter.\n    \n        :param resource_path: Path to method endpoint.\n        :param method: Method to call.\n        :param path_params: Path parameters in the url.\n        :param query_params: Query parameters in the url.\n        :param header_params: Header parameters to be\n            placed in the request header.\n        :param body: Request body.\n        :param post_params dict: Request post form parameters,\n            for `application/x-www-form-urlencoded`, `multipart/form-data`.\n        :param auth_settings list: Auth Settings names for the request.\n        :param response: Response data type.\n        :param files dict: key -> filename, value -> filepath,\n            for `multipart/form-data`.\n        :param async_req bool: execute request asynchronously\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param collection_formats: dict of collection formats for path, query,\n            header, and post parameters.\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return:\n            If async_req parameter is True,\n            the request will be called asynchronously.\n            The method will return the request thread.\n            If parameter async_req is False or missing,\n            then the method will return the response directly.\n        \"\"\"\n        if not async_req:\n>           return self.__call_api(resource_path, method,\n                                   path_params, query_params, header_params,\n                                   body, post_params, files,\n                                   response_type, auth_settings,\n                                   _return_http_data_only, collection_formats,\n                                   _preload_content, _request_timeout, _host)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:348: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc201e1d750>\nresource_path = '/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-028f7809/llminferenceservices/router-with-refs-test'\nmethod = 'GET'\npath_params = [('group', 'serving.kserve.io'), ('version', 'v1alpha1'), ('namespace', 'e2e-test-llm-inference-service-028f7809'), ('plural', 'llminferenceservices'), ('name', 'router-with-refs-test')]\nquery_params = []\nheader_params = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def __call_api(\n            self, resource_path, method, path_params=None,\n            query_params=None, header_params=None, body=None, post_params=None,\n            files=None, response_type=None, auth_settings=None,\n            _return_http_data_only=None, collection_formats=None,\n            _preload_content=True, _request_timeout=None, _host=None):\n    \n        config = self.configuration\n    \n        # header parameters\n        header_params = header_params or {}\n        header_params.update(self.default_headers)\n        if self.cookie:\n            header_params['Cookie'] = self.cookie\n        if header_params:\n            header_params = self.sanitize_for_serialization(header_params)\n            header_params = dict(self.parameters_to_tuples(header_params,\n                                                           collection_formats))\n    \n        # path parameters\n        if path_params:\n            path_params = self.sanitize_for_serialization(path_params)\n            path_params = self.parameters_to_tuples(path_params,\n                                                    collection_formats)\n            for k, v in path_params:\n                # specified safe chars, encode everything\n                resource_path = resource_path.replace(\n                    '{%s}' % k,\n                    quote(str(v), safe=config.safe_chars_for_path_param)\n                )\n    \n        # query parameters\n        if query_params:\n            query_params = self.sanitize_for_serialization(query_params)\n            query_params = self.parameters_to_tuples(query_params,\n                                                     collection_formats)\n    \n        # post parameters\n        if post_params or files:\n            post_params = post_params if post_params else []\n            post_params = self.sanitize_for_serialization(post_params)\n            post_params = self.parameters_to_tuples(post_params,\n                                                    collection_formats)\n            post_params.extend(self.files_parameters(files))\n    \n        # auth setting\n        self.update_params_for_auth(header_params, query_params, auth_settings)\n    \n        # body\n        if body:\n            body = self.sanitize_for_serialization(body)\n    \n        # request url\n        if _host is None:\n            url = self.configuration.host + resource_path\n        else:\n            # use server/host defined in path or operation instead\n            url = _host + resource_path\n    \n        # perform request and return response\n>       response_data = self.request(\n            method, url, query_params=query_params, headers=header_params,\n            post_params=post_params, body=body,\n            _preload_content=_preload_content,\n            _request_timeout=_request_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:180: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc201e1d750>\nmethod = 'GET'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-028f7809/llminferenceservices/router-with-refs-test'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\npost_params = [], body = None, _preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                post_params=None, body=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Makes the HTTP request using RESTClient.\"\"\"\n        if method == \"GET\":\n>           return self.rest_client.GET(url,\n                                        query_params=query_params,\n                                        _preload_content=_preload_content,\n                                        _request_timeout=_request_timeout,\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:373: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc201e1e790>\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-028f7809/llminferenceservices/router-with-refs-test'\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nquery_params = [], _preload_content = True, _request_timeout = None\n\n    def GET(self, url, headers=None, query_params=None, _preload_content=True,\n            _request_timeout=None):\n>       return self.request(\"GET\", url,\n                            headers=headers,\n                            _preload_content=_preload_content,\n                            _request_timeout=_request_timeout,\n                            query_params=query_params)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:244: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc201e1e790>\nmethod = 'GET'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-028f7809/llminferenceservices/router-with-refs-test'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = {}, _preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                body=None, post_params=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Perform requests.\n    \n        :param method: http request method\n        :param url: http request url\n        :param query_params: query parameters in the url\n        :param headers: http request headers\n        :param body: request json body, for `application/json`\n        :param post_params: request post parameters,\n                            `application/x-www-form-urlencoded`\n                            and `multipart/form-data`\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        \"\"\"\n        method = method.upper()\n        assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',\n                          'PATCH', 'OPTIONS']\n    \n        if post_params and body:\n            raise ApiValueError(\n                \"body parameter cannot be used with post_params parameter.\"\n            )\n    \n        post_params = post_params or {}\n        headers = headers or {}\n    \n        timeout = None\n        if _request_timeout:\n            if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)):  # noqa: E501,F821\n                timeout = urllib3.Timeout(total=_request_timeout)\n            elif (isinstance(_request_timeout, tuple) and\n                  len(_request_timeout) == 2):\n                timeout = urllib3.Timeout(\n                    connect=_request_timeout[0], read=_request_timeout[1])\n    \n        if 'Content-Type' not in headers:\n            headers['Content-Type'] = 'application/json'\n    \n        try:\n            # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`\n            if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:\n                if query_params:\n                    url += '?' + urlencode(query_params)\n                if (re.search('json', headers['Content-Type'], re.IGNORECASE) or\n                        headers['Content-Type'] == 'application/apply-patch+yaml'):\n                    if headers['Content-Type'] == 'application/json-patch+json':\n                        if not isinstance(body, list):\n                            headers['Content-Type'] = \\\n                                'application/strategic-merge-patch+json'\n                    request_body = None\n                    if body is not None:\n                        request_body = json.dumps(body)\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'application/x-www-form-urlencoded':  # noqa: E501\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=False,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'multipart/form-data':\n                    # must del headers['Content-Type'], or the correct\n                    # Content-Type which generated by urllib3 will be\n                    # overwritten.\n                    del headers['Content-Type']\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=True,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                # Pass a `string` parameter directly in the body to support\n                # other content types than Json when `body` argument is\n                # provided in serialized form\n                elif isinstance(body, str) or isinstance(body, bytes):\n                    request_body = body\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                else:\n                    # Cannot generate the request from given parameters\n                    msg = \"\"\"Cannot prepare a request message for provided\n                             arguments. Please check that your arguments match\n                             declared content type.\"\"\"\n                    raise ApiException(status=0, reason=msg)\n            # For `GET`, `HEAD`\n            else:\n                r = self.pool_manager.request(method, url,\n                                              fields=query_params,\n                                              preload_content=_preload_content,\n                                              timeout=timeout,\n                                              headers=headers)\n        except urllib3.exceptions.SSLError as e:\n            msg = \"{0}\\n{1}\".format(type(e).__name__, str(e))\n            raise ApiException(status=0, reason=msg)\n    \n        if _preload_content:\n            r = RESTResponse(r)\n    \n            # In the python 3, the response.data is bytes.\n            # we need to decode it to string.\n            if six.PY3:\n                r.data = r.data.decode('utf8')\n    \n            # log response body\n            logger.debug(\"response body: %s\", r.data)\n    \n        if not 200 <= r.status <= 299:\n>           raise ApiException(http_resp=r)\nE           kubernetes.client.exceptions.ApiException: (500)\nE           Reason: Internal Server Error\nE           HTTP response headers: HTTPHeaderDict({'Audit-Id': '8d52e004-35ea-4781-b7af-47e2b20be695', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:04 GMT', 'Content-Length': '264'})\nE           HTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"conversion webhook for serving.kserve.io/v1alpha2, Kind=LLMInferenceService failed: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/convert?timeout=30s\\\": EOF\",\"code\":500}\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:238: ApiException\n\nThe above exception was the direct cause of the following exception:\n\ntest_case = TestCase(base_refs=['router-with-refs', 'scheduler-managed', 'workload-single-cpu', 'model-fb-opt-125m'], prompt='KSer...              {'name': 'model-fb-opt-125m-router-with-r-6d64416a'}]},\n 'status': None}, model_name='facebook/opt-125m')\n\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-gateway-1\",\n                    before_test=[\n                        lambda tc: create_router_resources(\n                            gateways=[\n                                make_router_gateway(\n                                    \"router-gateway-1\",\n                                    tc.namespace,\n                                ),\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.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-gateway-1\",\n                    before_test=[\n                        lambda tc: create_router_resources(\n                            gateways=[\n                                make_router_gateway(\n                                    \"router-gateway-1\",\n                                    tc.namespace,\n                                ),\n                            ],\n                            routes=[\n                                make_router_main_route(\n                                    \"router-route-1\",\n                                    tc.namespace,\n                                    \"router-gateway-1\",\n                                    \"router-with-refs-test\",\n                                ),\n                                make_router_health_route(\n                                    \"router-route-2\",\n                                    tc.namespace,\n                                    \"router-gateway-1\",\n                                    \"router-with-refs-test\",\n                                ),\n                            ],\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-gateway-2\",\n                    before_test=[\n                        lambda tc: create_router_resources(\n                            gateways=[\n                                make_router_gateway(\n                                    \"router-gateway-2\",\n                                    tc.namespace,\n                                ),\n                            ],\n                            routes=[\n                                make_router_main_route(\n                                    \"router-route-3\",\n                                    tc.namespace,\n                                    \"router-gateway-2\",\n                                    \"router-with-refs-pd-test\",\n                                ),\n                                make_router_health_route(\n                                    \"router-route-4\",\n                                    tc.namespace,\n                                    \"router-gateway-2\",\n                                    \"router-with-refs-pd-test\",\n                                ),\n                            ],\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=[\n                        lambda tc: create_scheduler_configmap(namespace=tc.namespace)\n                    ],\n                    after_test=[\n                        lambda tc: delete_scheduler_configmap(namespace=tc.namespace)\n                    ],\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            # Standalone tokenizer \u2014 clean path: token-producer in inline config\n            pytest.param(\n                TestCase(\n                    base_refs=[\n                        \"router-managed\",\n                        \"scheduler-with-tokenizer-kvcache\",\n                        \"workload-llmd-simulator-kvcache\",\n                    ],\n                    prompt=\"KServe is a\",\n                    service_name=\"tokenizer-clean-path-test\",\n                ),\n                marks=[\n                    pytest.mark.cluster_cpu,\n                    pytest.mark.cluster_single_node,\n                    pytest.mark.llmd_simulator,\n                ],\n            ),\n            # Standalone tokenizer \u2014 migration path: legacy precise-prefix-cache-scorer\n            # triggers auto-provisioned tokenizer without explicit tokenizer:{} field\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=\"tokenizer-migration-path-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: \"publishers/{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: \"publishers/{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: \"publishers/{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: \"publishers/{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=\"publishers/{namespace}/models/lora-adapter-1\",\n                    payload_formatter=completions_payload,\n                    response_assertion=assert_model_field_matches(\n                        \"publishers/{namespace}/models/lora-adapter-1\"\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: \"publishers/{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                        \"publishers/{namespace}/models/facebook/opt-125m\",\n                        \"lora-adapter-1\",\n                        \"publishers/{namespace}/models/lora-adapter-1\",\n                    ),\n                    url_getter=get_model_routing_url,\n                    extra_headers={\n                        MODEL_ROUTING_HEADER: \"publishers/{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=[lambda tc: ensure_pvc_with_model(namespace=tc.namespace)],\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=[lambda tc: ensure_pvc_with_model(namespace=tc.namespace)],\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=[lambda tc: ensure_pvc_with_model(namespace=tc.namespace)],\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        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\nllmisvc/test_llm_inference_service.py:866: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<kserve.api.kserve_client.KServeClient object at 0x7fc201cf8f50>, {'api_version': 'serving.kserve.io/v1alpha1',\n 'kin...-with-ec5d4bfa'},\n                       {'name': 'model-fb-opt-125m-router-with-r-6d64416a'}]},\n 'status': None}, 900)\nkwargs = {}, func_name = 'wait_for_llm_isvc_ready'\ntimestamp_start = '2026-07-28T17:22:22.706303', start_time = 1785259342.706591\nduration = 102.21241092681885, timestamp_end = '2026-07-28T17:24:04.919006'\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 0x7fc201cf8f50>\ngiven = {'api_version': 'serving.kserve.io/v1alpha1',\n 'kind': 'LLMInferenceService',\n 'metadata': {'annotations': {'security....router-with-ec5d4bfa'},\n                       {'name': 'model-fb-opt-125m-router-with-r-6d64416a'}]},\n 'status': None}\ntimeout_seconds = 900\n\n    @log_execution\n    def wait_for_llm_isvc_ready(\n        kserve_client: KServeClient,\n        given: V1alpha1LLMInferenceService,\n        timeout_seconds: int = 900,\n    ) -> str:\n        def assert_llm_isvc_ready():\n            out = get_llmisvc(\n                kserve_client,\n                given.metadata.name,\n                given.metadata.namespace,\n                given.api_version.split(\"/\")[1],\n            )\n    \n            if \"status\" not in out:\n                raise AssertionError(\"No status found in LLM inference service\")\n    \n            status = out[\"status\"]\n            if \"conditions\" not in status:\n                raise AssertionError(\"No conditions found in status\")\n    \n            expected_true_conditions = {\"Ready\", \"WorkloadsReady\", \"RouterReady\"}\n            got_true_conditions = set()\n            all_condition_types = set()\n    \n            conditions = status[\"conditions\"]\n    \n            for condition in conditions:\n                ctype = condition.get(\"type\")\n                all_condition_types.add(ctype)\n                if condition.get(\"status\") == \"True\":\n                    got_true_conditions.add(ctype)\n    \n            # When TokenizerReady is present, it must also be True\n            if \"TokenizerReady\" in all_condition_types:\n                expected_true_conditions.add(\"TokenizerReady\")\n    \n            missing_conditions = expected_true_conditions - got_true_conditions\n            if missing_conditions:\n                raise AssertionError(\n                    f\"Missing true conditions: {missing_conditions}, expected {expected_true_conditions}, got {conditions}\"\n                )\n            return True\n    \n>       return wait_for(assert_llm_isvc_ready, timeout=timeout_seconds, interval=1.0)\n\nllmisvc/test_llm_inference_service.py:1376: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nassertion_fn = <function wait_for_llm_isvc_ready.<locals>.assert_llm_isvc_ready at 0x7fc2021b6020>\ntimeout = 900, interval = 1.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:1387: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def assert_llm_isvc_ready():\n>       out = get_llmisvc(\n            kserve_client,\n            given.metadata.name,\n            given.metadata.namespace,\n            given.api_version.split(\"/\")[1],\n        )\n\nllmisvc/test_llm_inference_service.py:1339: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7fc201cf8f50>\nname = 'router-with-refs-test'\nnamespace = 'e2e-test-llm-inference-service-028f7809', version = 'v1alpha1'\n\n    def get_llmisvc(\n        kserve_client: KServeClient,\n        name,\n        namespace,\n        version=constants.KSERVE_V1ALPHA1_VERSION,\n    ):\n        try:\n            return kserve_client.api_instance.get_namespaced_custom_object(\n                constants.KSERVE_GROUP,\n                version,\n                namespace,\n                KSERVE_PLURAL_LLMINFERENCESERVICE,\n                name,\n            )\n        except client.rest.ApiException as e:\n>           raise RuntimeError(\n                f\"\u274c Exception when calling CustomObjectsApi->\"\n                f\"get_namespaced_custom_object for LLMInferenceService: {e}\"\n            ) from e\nE           RuntimeError: \u274c Exception when calling CustomObjectsApi->get_namespaced_custom_object for LLMInferenceService: (500)\nE           Reason: Internal Server Error\nE           HTTP response headers: HTTPHeaderDict({'Audit-Id': '8d52e004-35ea-4781-b7af-47e2b20be695', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:04 GMT', 'Content-Length': '264'})\nE           HTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"conversion webhook for serving.kserve.io/v1alpha2, Kind=LLMInferenceService failed: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/convert?timeout=30s\\\": EOF\",\"code\":500}\n\nllmisvc/test_llm_inference_service.py:1212: RuntimeError"}, "teardown": {"duration": 0.00165521500093746, "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-pd-cpu-model-fb-opt-125m]", "lineno": 242, "outcome": "error", "keywords": ["test_llm_inference_service[router-managed-workload-pd-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-managed-workload-pd-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.1899159930035239, "outcome": "failed", "crash": {"path": "/workspace/source/python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py", "lineno": 238, "message": "kubernetes.client.exceptions.ApiException: (500)\nReason: Internal Server Error\nHTTP response headers: HTTPHeaderDict({'Audit-Id': '4b3f3cac-d2e3-4b14-beb8-d3bea22125be', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:06 GMT', 'Content-Length': '701'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Internal error occurred: failed calling webhook \\\"llminferenceserviceconfig.kserve-webhook-server.v1alpha1.validator\\\": failed to call webhook: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/validate-serving-kserve-io-v1alpha1-llminferenceserviceconfig?timeout=10s\\\": EOF\",\"reason\":\"InternalError\",\"details\":{\"causes\":[{\"message\":\"failed calling webhook \\\"llminferenceserviceconfig.kserve-webhook-server.v1alpha1.validator\\\": failed to call webhook: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/validate-serving-kserve-io-v1alpha1-llminferenceserviceconfig?timeout=10s\\\": EOF\"}]},\"code\":500}"}, "traceback": [{"path": "common/gateway_proxy_istio.py", "lineno": 183, "message": ""}, {"path": "llmisvc/fixtures.py", "lineno": 1611, "message": ""}, {"path": "llmisvc/fixtures.py", "lineno": 1573, "message": ""}, {"path": "llmisvc/fixtures.py", "lineno": 1747, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py", "lineno": 231, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py", "lineno": 354, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py", "lineno": 348, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py", "lineno": 180, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py", "lineno": 391, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py", "lineno": 279, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py", "lineno": 238, "message": "ApiException"}], "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7fc202413a90>\nllm_config = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\nnamespace = 'e2e-test-llm-inference-service-62876e81'\n\n    def _create_or_update_llmisvc_config(kserve_client, llm_config, namespace=None):\n        \"\"\"Create or update an LLMInferenceServiceConfig resource.\"\"\"\n        version = llm_config[\"apiVersion\"].split(\"/\")[1]\n    \n        if namespace is None:\n            namespace = llm_config.get(\"metadata\", {}).get(\"namespace\", \"default\")\n    \n        name = llm_config.get(\"metadata\", {}).get(\"name\")\n        if not name:\n            raise ValueError(\"LLMInferenceServiceConfig must have a name in metadata\")\n    \n        logger.info(f\"Checking LLMInferenceServiceConfig {name} in namespace {namespace}\")\n    \n        try:\n>           existing_config = kserve_client.api_instance.get_namespaced_custom_object(\n                constants.KSERVE_GROUP,\n                version,\n                namespace,\n                KSERVE_PLURAL_LLMINFERENCESERVICECONFIG,\n                name,\n            )\n\nllmisvc/fixtures.py:1721: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc202144590>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-62876e81'\nplural = 'llminferenceserviceconfigs'\nname = 'router-managed-llmisvc-model-fb-b69cdb68'\nkwargs = {'_return_http_data_only': True}\n\n    def get_namespaced_custom_object(self, group, version, namespace, plural, name, **kwargs):  # noqa: E501\n        \"\"\"get_namespaced_custom_object  # noqa: E501\n    \n        Returns a namespace scoped custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.get_namespaced_custom_object(group, version, namespace, plural, name, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: the custom resource's group (required)\n        :param str version: the custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: the custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param str name: the custom object's name (required)\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: object\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n        kwargs['_return_http_data_only'] = True\n>       return self.get_namespaced_custom_object_with_http_info(group, version, namespace, plural, name, **kwargs)  # noqa: E501\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:1632: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc202144590>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-62876e81'\nplural = 'llminferenceserviceconfigs'\nname = 'router-managed-llmisvc-model-fb-b69cdb68'\nkwargs = {'_return_http_data_only': True}\nlocal_var_params = {'_return_http_data_only': True, 'all_params': ['group', 'version', 'namespace', 'plural', 'name', 'async_req', ...], 'auth_settings': ['BearerToken'], 'body_params': None, ...}\nall_params = ['group', 'version', 'namespace', 'plural', 'name', 'async_req', ...]\nkey = '_return_http_data_only', val = True, collection_formats = {}\npath_params = {'group': 'serving.kserve.io', 'name': 'router-managed-llmisvc-model-fb-b69cdb68', 'namespace': 'e2e-test-llm-inference-service-62876e81', 'plural': 'llminferenceserviceconfigs', ...}\nquery_params = []\n\n    def get_namespaced_custom_object_with_http_info(self, group, version, namespace, plural, name, **kwargs):  # noqa: E501\n        \"\"\"get_namespaced_custom_object  # noqa: E501\n    \n        Returns a namespace scoped custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.get_namespaced_custom_object_with_http_info(group, version, namespace, plural, name, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: the custom resource's group (required)\n        :param str version: the custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: the custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param str name: the custom object's name (required)\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: tuple(object, status_code(int), headers(HTTPHeaderDict))\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n    \n        local_var_params = locals()\n    \n        all_params = [\n            'group',\n            'version',\n            'namespace',\n            'plural',\n            'name'\n        ]\n        all_params.extend(\n            [\n                'async_req',\n                '_return_http_data_only',\n                '_preload_content',\n                '_request_timeout'\n            ]\n        )\n    \n        for key, val in six.iteritems(local_var_params['kwargs']):\n            if key not in all_params:\n                raise ApiTypeError(\n                    \"Got an unexpected keyword argument '%s'\"\n                    \" to method get_namespaced_custom_object\" % key\n                )\n            local_var_params[key] = val\n        del local_var_params['kwargs']\n        # verify the required parameter 'group' is set\n        if self.api_client.client_side_validation and ('group' not in local_var_params or  # noqa: E501\n                                                        local_var_params['group'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `group` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'version' is set\n        if self.api_client.client_side_validation and ('version' not in local_var_params or  # noqa: E501\n                                                        local_var_params['version'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `version` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'namespace' is set\n        if self.api_client.client_side_validation and ('namespace' not in local_var_params or  # noqa: E501\n                                                        local_var_params['namespace'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `namespace` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'plural' is set\n        if self.api_client.client_side_validation and ('plural' not in local_var_params or  # noqa: E501\n                                                        local_var_params['plural'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `plural` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'name' is set\n        if self.api_client.client_side_validation and ('name' not in local_var_params or  # noqa: E501\n                                                        local_var_params['name'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `name` when calling `get_namespaced_custom_object`\")  # noqa: E501\n    \n        collection_formats = {}\n    \n        path_params = {}\n        if 'group' in local_var_params:\n            path_params['group'] = local_var_params['group']  # noqa: E501\n        if 'version' in local_var_params:\n            path_params['version'] = local_var_params['version']  # noqa: E501\n        if 'namespace' in local_var_params:\n            path_params['namespace'] = local_var_params['namespace']  # noqa: E501\n        if 'plural' in local_var_params:\n            path_params['plural'] = local_var_params['plural']  # noqa: E501\n        if 'name' in local_var_params:\n            path_params['name'] = local_var_params['name']  # noqa: E501\n    \n        query_params = []\n    \n        header_params = {}\n    \n        form_params = []\n        local_var_files = {}\n    \n        body_params = None\n        # HTTP header `Accept`\n        header_params['Accept'] = self.api_client.select_header_accept(\n            ['application/json'])  # noqa: E501\n    \n        # Authentication setting\n        auth_settings = ['BearerToken']  # noqa: E501\n    \n>       return self.api_client.call_api(\n            '/apis/{group}/{version}/namespaces/{namespace}/{plural}/{name}', 'GET',\n            path_params,\n            query_params,\n            header_params,\n            body=body_params,\n            post_params=form_params,\n            files=local_var_files,\n            response_type='object',  # noqa: E501\n            auth_settings=auth_settings,\n            async_req=local_var_params.get('async_req'),\n            _return_http_data_only=local_var_params.get('_return_http_data_only'),  # noqa: E501\n            _preload_content=local_var_params.get('_preload_content', True),\n            _request_timeout=local_var_params.get('_request_timeout'),\n            collection_formats=collection_formats)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:1739: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202144d90>\nresource_path = '/apis/{group}/{version}/namespaces/{namespace}/{plural}/{name}'\nmethod = 'GET'\npath_params = {'group': 'serving.kserve.io', 'name': 'router-managed-llmisvc-model-fb-b69cdb68', 'namespace': 'e2e-test-llm-inference-service-62876e81', 'plural': 'llminferenceserviceconfigs', ...}\nquery_params = []\nheader_params = {'Accept': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], async_req = None, _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def call_api(self, resource_path, method,\n                 path_params=None, query_params=None, header_params=None,\n                 body=None, post_params=None, files=None,\n                 response_type=None, auth_settings=None, async_req=None,\n                 _return_http_data_only=None, collection_formats=None,\n                 _preload_content=True, _request_timeout=None, _host=None):\n        \"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\n    \n        To make an async_req request, set the async_req parameter.\n    \n        :param resource_path: Path to method endpoint.\n        :param method: Method to call.\n        :param path_params: Path parameters in the url.\n        :param query_params: Query parameters in the url.\n        :param header_params: Header parameters to be\n            placed in the request header.\n        :param body: Request body.\n        :param post_params dict: Request post form parameters,\n            for `application/x-www-form-urlencoded`, `multipart/form-data`.\n        :param auth_settings list: Auth Settings names for the request.\n        :param response: Response data type.\n        :param files dict: key -> filename, value -> filepath,\n            for `multipart/form-data`.\n        :param async_req bool: execute request asynchronously\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param collection_formats: dict of collection formats for path, query,\n            header, and post parameters.\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return:\n            If async_req parameter is True,\n            the request will be called asynchronously.\n            The method will return the request thread.\n            If parameter async_req is False or missing,\n            then the method will return the response directly.\n        \"\"\"\n        if not async_req:\n>           return self.__call_api(resource_path, method,\n                                   path_params, query_params, header_params,\n                                   body, post_params, files,\n                                   response_type, auth_settings,\n                                   _return_http_data_only, collection_formats,\n                                   _preload_content, _request_timeout, _host)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:348: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202144d90>\nresource_path = '/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-62876e81/llminferenceserviceconfigs/router-managed-llmisvc-model-fb-b69cdb68'\nmethod = 'GET'\npath_params = [('group', 'serving.kserve.io'), ('version', 'v1alpha1'), ('namespace', 'e2e-test-llm-inference-service-62876e81'), ('plural', 'llminferenceserviceconfigs'), ('name', 'router-managed-llmisvc-model-fb-b69cdb68')]\nquery_params = []\nheader_params = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def __call_api(\n            self, resource_path, method, path_params=None,\n            query_params=None, header_params=None, body=None, post_params=None,\n            files=None, response_type=None, auth_settings=None,\n            _return_http_data_only=None, collection_formats=None,\n            _preload_content=True, _request_timeout=None, _host=None):\n    \n        config = self.configuration\n    \n        # header parameters\n        header_params = header_params or {}\n        header_params.update(self.default_headers)\n        if self.cookie:\n            header_params['Cookie'] = self.cookie\n        if header_params:\n            header_params = self.sanitize_for_serialization(header_params)\n            header_params = dict(self.parameters_to_tuples(header_params,\n                                                           collection_formats))\n    \n        # path parameters\n        if path_params:\n            path_params = self.sanitize_for_serialization(path_params)\n            path_params = self.parameters_to_tuples(path_params,\n                                                    collection_formats)\n            for k, v in path_params:\n                # specified safe chars, encode everything\n                resource_path = resource_path.replace(\n                    '{%s}' % k,\n                    quote(str(v), safe=config.safe_chars_for_path_param)\n                )\n    \n        # query parameters\n        if query_params:\n            query_params = self.sanitize_for_serialization(query_params)\n            query_params = self.parameters_to_tuples(query_params,\n                                                     collection_formats)\n    \n        # post parameters\n        if post_params or files:\n            post_params = post_params if post_params else []\n            post_params = self.sanitize_for_serialization(post_params)\n            post_params = self.parameters_to_tuples(post_params,\n                                                    collection_formats)\n            post_params.extend(self.files_parameters(files))\n    \n        # auth setting\n        self.update_params_for_auth(header_params, query_params, auth_settings)\n    \n        # body\n        if body:\n            body = self.sanitize_for_serialization(body)\n    \n        # request url\n        if _host is None:\n            url = self.configuration.host + resource_path\n        else:\n            # use server/host defined in path or operation instead\n            url = _host + resource_path\n    \n        # perform request and return response\n>       response_data = self.request(\n            method, url, query_params=query_params, headers=header_params,\n            post_params=post_params, body=body,\n            _preload_content=_preload_content,\n            _request_timeout=_request_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:180: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202144d90>\nmethod = 'GET'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1a...namespaces/e2e-test-llm-inference-service-62876e81/llminferenceserviceconfigs/router-managed-llmisvc-model-fb-b69cdb68'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\npost_params = [], body = None, _preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                post_params=None, body=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Makes the HTTP request using RESTClient.\"\"\"\n        if method == \"GET\":\n>           return self.rest_client.GET(url,\n                                        query_params=query_params,\n                                        _preload_content=_preload_content,\n                                        _request_timeout=_request_timeout,\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:373: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc202147a50>\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1a...namespaces/e2e-test-llm-inference-service-62876e81/llminferenceserviceconfigs/router-managed-llmisvc-model-fb-b69cdb68'\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nquery_params = [], _preload_content = True, _request_timeout = None\n\n    def GET(self, url, headers=None, query_params=None, _preload_content=True,\n            _request_timeout=None):\n>       return self.request(\"GET\", url,\n                            headers=headers,\n                            _preload_content=_preload_content,\n                            _request_timeout=_request_timeout,\n                            query_params=query_params)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:244: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc202147a50>\nmethod = 'GET'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1a...namespaces/e2e-test-llm-inference-service-62876e81/llminferenceserviceconfigs/router-managed-llmisvc-model-fb-b69cdb68'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = {}, _preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                body=None, post_params=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Perform requests.\n    \n        :param method: http request method\n        :param url: http request url\n        :param query_params: query parameters in the url\n        :param headers: http request headers\n        :param body: request json body, for `application/json`\n        :param post_params: request post parameters,\n                            `application/x-www-form-urlencoded`\n                            and `multipart/form-data`\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        \"\"\"\n        method = method.upper()\n        assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',\n                          'PATCH', 'OPTIONS']\n    \n        if post_params and body:\n            raise ApiValueError(\n                \"body parameter cannot be used with post_params parameter.\"\n            )\n    \n        post_params = post_params or {}\n        headers = headers or {}\n    \n        timeout = None\n        if _request_timeout:\n            if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)):  # noqa: E501,F821\n                timeout = urllib3.Timeout(total=_request_timeout)\n            elif (isinstance(_request_timeout, tuple) and\n                  len(_request_timeout) == 2):\n                timeout = urllib3.Timeout(\n                    connect=_request_timeout[0], read=_request_timeout[1])\n    \n        if 'Content-Type' not in headers:\n            headers['Content-Type'] = 'application/json'\n    \n        try:\n            # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`\n            if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:\n                if query_params:\n                    url += '?' + urlencode(query_params)\n                if (re.search('json', headers['Content-Type'], re.IGNORECASE) or\n                        headers['Content-Type'] == 'application/apply-patch+yaml'):\n                    if headers['Content-Type'] == 'application/json-patch+json':\n                        if not isinstance(body, list):\n                            headers['Content-Type'] = \\\n                                'application/strategic-merge-patch+json'\n                    request_body = None\n                    if body is not None:\n                        request_body = json.dumps(body)\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'application/x-www-form-urlencoded':  # noqa: E501\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=False,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'multipart/form-data':\n                    # must del headers['Content-Type'], or the correct\n                    # Content-Type which generated by urllib3 will be\n                    # overwritten.\n                    del headers['Content-Type']\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=True,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                # Pass a `string` parameter directly in the body to support\n                # other content types than Json when `body` argument is\n                # provided in serialized form\n                elif isinstance(body, str) or isinstance(body, bytes):\n                    request_body = body\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                else:\n                    # Cannot generate the request from given parameters\n                    msg = \"\"\"Cannot prepare a request message for provided\n                             arguments. Please check that your arguments match\n                             declared content type.\"\"\"\n                    raise ApiException(status=0, reason=msg)\n            # For `GET`, `HEAD`\n            else:\n                r = self.pool_manager.request(method, url,\n                                              fields=query_params,\n                                              preload_content=_preload_content,\n                                              timeout=timeout,\n                                              headers=headers)\n        except urllib3.exceptions.SSLError as e:\n            msg = \"{0}\\n{1}\".format(type(e).__name__, str(e))\n            raise ApiException(status=0, reason=msg)\n    \n        if _preload_content:\n            r = RESTResponse(r)\n    \n            # In the python 3, the response.data is bytes.\n            # we need to decode it to string.\n            if six.PY3:\n                r.data = r.data.decode('utf8')\n    \n            # log response body\n            logger.debug(\"response body: %s\", r.data)\n    \n        if not 200 <= r.status <= 299:\n>           raise ApiException(http_resp=r)\nE           kubernetes.client.exceptions.ApiException: (404)\nE           Reason: Not Found\nE           HTTP response headers: HTTPHeaderDict({'Audit-Id': '1c81504e-9421-406f-9182-f2e84d2c5efd', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:06 GMT', 'Content-Length': '338'})\nE           HTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"llminferenceserviceconfigs.serving.kserve.io \\\"router-managed-llmisvc-model-fb-b69cdb68\\\" not found\",\"reason\":\"NotFound\",\"details\":{\"name\":\"router-managed-llmisvc-model-fb-b69cdb68\",\"group\":\"serving.kserve.io\",\"kind\":\"llminferenceserviceconfigs\"},\"code\":404}\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:238: ApiException\n\nDuring handling of the above exception, another exception occurred:\n\nrequest = <SubRequest 'ensure_gateway_proxy_memory' for <Function test_llm_inference_service[router-managed-workload-pd-cpu-model-fb-opt-125m]>>\n\n    @pytest.fixture(autouse=True)\n    def ensure_gateway_proxy_memory(request):\n        \"\"\"After test setup creates gateways, patch them for proxy memory.\"\"\"\n        if not GATEWAY_PROXY_MEMORY:\n            return\n    \n        # Let test_case (llmisvc) create gateways first\n    \n        if \"test_case\" in request.fixturenames:\n>           request.getfixturevalue(\"test_case\")\n\ncommon/gateway_proxy_istio.py:183: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nrequest = <SubRequest 'test_case' for <Function test_llm_inference_service[router-managed-workload-pd-cpu-model-fb-opt-125m]>>\ntest_namespace = 'e2e-test-llm-inference-service-62876e81'\n\n    @pytest.fixture(scope=\"function\")\n    def test_case(request, test_namespace):\n        tc = request.param\n        ns = test_namespace\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        tc.namespace = ns\n        for peer in tc.peers:\n            peer.namespace = ns\n    \n        for func in tc.before_test:\n            func(tc)\n    \n>       _setup_test_case_service(kserve_client, tc, request.node.name, namespace=ns)\n\nllmisvc/fixtures.py:1611: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7fc202413a90>\ntc = TestCase(base_refs=['router-managed', 'workload-pd-cpu', 'model-fb-opt-125m'], prompt='You are an expert in Kubernetes...inference-service-62876e81', before_test=[], after_test=[], peers=[], llm_service=None, model_name='facebook/opt-125m')\ntest_node_name = 'test_llm_inference_service[router-managed-workload-pd-cpu-model-fb-opt-125m]'\nnamespace = 'e2e-test-llm-inference-service-62876e81', peer_index = None\n\n    def _setup_test_case_service(\n        kserve_client, tc, test_node_name, namespace, peer_index=None\n    ):\n        \"\"\"Create LLMInferenceServiceConfigs and build the LLMInferenceService for a TestCase.\n    \n        Returns a list of created config names for cleanup tracking.\n        \"\"\"\n        missing_refs = [\n            ref for ref in tc.base_refs if ref not in LLMINFERENCESERVICE_CONFIGS\n        ]\n        if missing_refs:\n            raise ValueError(\n                f\"Missing base_refs in LLMINFERENCESERVICE_CONFIGS: {missing_refs}\"\n            )\n        if not tc.service_name:\n            suffix = f\"-peer-{peer_index}\" if peer_index is not None else \"\"\n            tc.service_name = generate_service_name(test_node_name + suffix, tc.base_refs)\n        if tc.model_name == \"default/model\":\n            tc.model_name = _get_model_name_from_configs(tc.base_refs)\n        elif \"{namespace}\" in tc.model_name:\n            tc.model_name = tc.model_name.format(namespace=namespace)\n    \n        created_configs = []\n        unique_base_refs = []\n        for base_ref in tc.base_refs:\n            unique_config_name = generate_k8s_safe_suffix(base_ref, [tc.service_name])\n            unique_base_refs.append(unique_config_name)\n    \n            config = LLMINFERENCESERVICE_CONFIGS[base_ref]\n            spec = config(namespace) if callable(config) else copy.deepcopy(config)\n    \n            unique_config_body = {\n                \"apiVersion\": \"serving.kserve.io/v1alpha1\",\n                \"kind\": \"LLMInferenceServiceConfig\",\n                \"metadata\": {\n                    \"name\": unique_config_name,\n                    \"namespace\": namespace,\n                },\n                \"spec\": spec,\n            }\n    \n>           _create_or_update_llmisvc_config(kserve_client, unique_config_body, namespace)\n\nllmisvc/fixtures.py:1573: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7fc202413a90>\nllm_config = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\nnamespace = 'e2e-test-llm-inference-service-62876e81'\n\n    def _create_or_update_llmisvc_config(kserve_client, llm_config, namespace=None):\n        \"\"\"Create or update an LLMInferenceServiceConfig resource.\"\"\"\n        version = llm_config[\"apiVersion\"].split(\"/\")[1]\n    \n        if namespace is None:\n            namespace = llm_config.get(\"metadata\", {}).get(\"namespace\", \"default\")\n    \n        name = llm_config.get(\"metadata\", {}).get(\"name\")\n        if not name:\n            raise ValueError(\"LLMInferenceServiceConfig must have a name in metadata\")\n    \n        logger.info(f\"Checking LLMInferenceServiceConfig {name} in namespace {namespace}\")\n    \n        try:\n            existing_config = kserve_client.api_instance.get_namespaced_custom_object(\n                constants.KSERVE_GROUP,\n                version,\n                namespace,\n                KSERVE_PLURAL_LLMINFERENCESERVICECONFIG,\n                name,\n            )\n    \n            llm_config[\"metadata\"] = existing_config[\"metadata\"]\n    \n            outputs = kserve_client.api_instance.replace_namespaced_custom_object(\n                constants.KSERVE_GROUP,\n                version,\n                namespace,\n                KSERVE_PLURAL_LLMINFERENCESERVICECONFIG,\n                name,\n                llm_config,\n            )\n            logger.info(f\"\u2713 Successfully updated LLMInferenceServiceConfig {name}\")\n            return outputs\n    \n        except client.rest.ApiException as e:\n            if e.status == 404:  # Not found - create it\n                logger.info(\n                    f\"Resource not found, creating LLMInferenceServiceConfig {name}\"\n                )\n>               outputs = kserve_client.api_instance.create_namespaced_custom_object(\n                    constants.KSERVE_GROUP,\n                    version,\n                    namespace,\n                    KSERVE_PLURAL_LLMINFERENCESERVICECONFIG,\n                    llm_config,\n                )\n\nllmisvc/fixtures.py:1747: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc202144590>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-62876e81'\nplural = 'llminferenceserviceconfigs'\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\nkwargs = {'_return_http_data_only': True}\n\n    def create_namespaced_custom_object(self, group, version, namespace, plural, body, **kwargs):  # noqa: E501\n        \"\"\"create_namespaced_custom_object  # noqa: E501\n    \n        Creates a namespace scoped Custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.create_namespaced_custom_object(group, version, namespace, plural, body, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: The custom resource's group name (required)\n        :param str version: The custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: The custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param object body: The JSON schema of the Resource to create. (required)\n        :param str pretty: If 'true', then the output is pretty printed.\n        :param str dry_run: When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed\n        :param str field_manager: fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.\n        :param str field_validation: fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. (optional)\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: object\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n        kwargs['_return_http_data_only'] = True\n>       return self.create_namespaced_custom_object_with_http_info(group, version, namespace, plural, body, **kwargs)  # noqa: E501\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:231: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc202144590>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-62876e81'\nplural = 'llminferenceserviceconfigs'\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\nkwargs = {'_return_http_data_only': True}\nlocal_var_params = {'_return_http_data_only': True, 'all_params': ['group', 'version', 'namespace', 'plural', 'body', 'pretty', ...], 'au...e-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [...]}}}}}, ...}\nall_params = ['group', 'version', 'namespace', 'plural', 'body', 'pretty', ...]\nkey = '_return_http_data_only', val = True, collection_formats = {}\npath_params = {'group': 'serving.kserve.io', 'namespace': 'e2e-test-llm-inference-service-62876e81', 'plural': 'llminferenceserviceconfigs', 'version': 'v1alpha1'}\nquery_params = []\n\n    def create_namespaced_custom_object_with_http_info(self, group, version, namespace, plural, body, **kwargs):  # noqa: E501\n        \"\"\"create_namespaced_custom_object  # noqa: E501\n    \n        Creates a namespace scoped Custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.create_namespaced_custom_object_with_http_info(group, version, namespace, plural, body, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: The custom resource's group name (required)\n        :param str version: The custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: The custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param object body: The JSON schema of the Resource to create. (required)\n        :param str pretty: If 'true', then the output is pretty printed.\n        :param str dry_run: When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed\n        :param str field_manager: fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.\n        :param str field_validation: fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. (optional)\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: tuple(object, status_code(int), headers(HTTPHeaderDict))\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n    \n        local_var_params = locals()\n    \n        all_params = [\n            'group',\n            'version',\n            'namespace',\n            'plural',\n            'body',\n            'pretty',\n            'dry_run',\n            'field_manager',\n            'field_validation'\n        ]\n        all_params.extend(\n            [\n                'async_req',\n                '_return_http_data_only',\n                '_preload_content',\n                '_request_timeout'\n            ]\n        )\n    \n        for key, val in six.iteritems(local_var_params['kwargs']):\n            if key not in all_params:\n                raise ApiTypeError(\n                    \"Got an unexpected keyword argument '%s'\"\n                    \" to method create_namespaced_custom_object\" % key\n                )\n            local_var_params[key] = val\n        del local_var_params['kwargs']\n        # verify the required parameter 'group' is set\n        if self.api_client.client_side_validation and ('group' not in local_var_params or  # noqa: E501\n                                                        local_var_params['group'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `group` when calling `create_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'version' is set\n        if self.api_client.client_side_validation and ('version' not in local_var_params or  # noqa: E501\n                                                        local_var_params['version'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `version` when calling `create_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'namespace' is set\n        if self.api_client.client_side_validation and ('namespace' not in local_var_params or  # noqa: E501\n                                                        local_var_params['namespace'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `namespace` when calling `create_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'plural' is set\n        if self.api_client.client_side_validation and ('plural' not in local_var_params or  # noqa: E501\n                                                        local_var_params['plural'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `plural` when calling `create_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'body' is set\n        if self.api_client.client_side_validation and ('body' not in local_var_params or  # noqa: E501\n                                                        local_var_params['body'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `body` when calling `create_namespaced_custom_object`\")  # noqa: E501\n    \n        collection_formats = {}\n    \n        path_params = {}\n        if 'group' in local_var_params:\n            path_params['group'] = local_var_params['group']  # noqa: E501\n        if 'version' in local_var_params:\n            path_params['version'] = local_var_params['version']  # noqa: E501\n        if 'namespace' in local_var_params:\n            path_params['namespace'] = local_var_params['namespace']  # noqa: E501\n        if 'plural' in local_var_params:\n            path_params['plural'] = local_var_params['plural']  # noqa: E501\n    \n        query_params = []\n        if 'pretty' in local_var_params and local_var_params['pretty'] is not None:  # noqa: E501\n            query_params.append(('pretty', local_var_params['pretty']))  # noqa: E501\n        if 'dry_run' in local_var_params and local_var_params['dry_run'] is not None:  # noqa: E501\n            query_params.append(('dryRun', local_var_params['dry_run']))  # noqa: E501\n        if 'field_manager' in local_var_params and local_var_params['field_manager'] is not None:  # noqa: E501\n            query_params.append(('fieldManager', local_var_params['field_manager']))  # noqa: E501\n        if 'field_validation' in local_var_params and local_var_params['field_validation'] is not None:  # noqa: E501\n            query_params.append(('fieldValidation', local_var_params['field_validation']))  # noqa: E501\n    \n        header_params = {}\n    \n        form_params = []\n        local_var_files = {}\n    \n        body_params = None\n        if 'body' in local_var_params:\n            body_params = local_var_params['body']\n        # HTTP header `Accept`\n        header_params['Accept'] = self.api_client.select_header_accept(\n            ['application/json'])  # noqa: E501\n    \n        # Authentication setting\n        auth_settings = ['BearerToken']  # noqa: E501\n    \n>       return self.api_client.call_api(\n            '/apis/{group}/{version}/namespaces/{namespace}/{plural}', 'POST',\n            path_params,\n            query_params,\n            header_params,\n            body=body_params,\n            post_params=form_params,\n            files=local_var_files,\n            response_type='object',  # noqa: E501\n            auth_settings=auth_settings,\n            async_req=local_var_params.get('async_req'),\n            _return_http_data_only=local_var_params.get('_return_http_data_only'),  # noqa: E501\n            _preload_content=local_var_params.get('_preload_content', True),\n            _request_timeout=local_var_params.get('_request_timeout'),\n            collection_formats=collection_formats)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:354: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202144d90>\nresource_path = '/apis/{group}/{version}/namespaces/{namespace}/{plural}'\nmethod = 'POST'\npath_params = {'group': 'serving.kserve.io', 'namespace': 'e2e-test-llm-inference-service-62876e81', 'plural': 'llminferenceserviceconfigs', 'version': 'v1alpha1'}\nquery_params = []\nheader_params = {'Accept': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\npost_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], async_req = None, _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def call_api(self, resource_path, method,\n                 path_params=None, query_params=None, header_params=None,\n                 body=None, post_params=None, files=None,\n                 response_type=None, auth_settings=None, async_req=None,\n                 _return_http_data_only=None, collection_formats=None,\n                 _preload_content=True, _request_timeout=None, _host=None):\n        \"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\n    \n        To make an async_req request, set the async_req parameter.\n    \n        :param resource_path: Path to method endpoint.\n        :param method: Method to call.\n        :param path_params: Path parameters in the url.\n        :param query_params: Query parameters in the url.\n        :param header_params: Header parameters to be\n            placed in the request header.\n        :param body: Request body.\n        :param post_params dict: Request post form parameters,\n            for `application/x-www-form-urlencoded`, `multipart/form-data`.\n        :param auth_settings list: Auth Settings names for the request.\n        :param response: Response data type.\n        :param files dict: key -> filename, value -> filepath,\n            for `multipart/form-data`.\n        :param async_req bool: execute request asynchronously\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param collection_formats: dict of collection formats for path, query,\n            header, and post parameters.\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return:\n            If async_req parameter is True,\n            the request will be called asynchronously.\n            The method will return the request thread.\n            If parameter async_req is False or missing,\n            then the method will return the response directly.\n        \"\"\"\n        if not async_req:\n>           return self.__call_api(resource_path, method,\n                                   path_params, query_params, header_params,\n                                   body, post_params, files,\n                                   response_type, auth_settings,\n                                   _return_http_data_only, collection_formats,\n                                   _preload_content, _request_timeout, _host)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:348: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202144d90>\nresource_path = '/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-62876e81/llminferenceserviceconfigs'\nmethod = 'POST'\npath_params = [('group', 'serving.kserve.io'), ('version', 'v1alpha1'), ('namespace', 'e2e-test-llm-inference-service-62876e81'), ('plural', 'llminferenceserviceconfigs')]\nquery_params = []\nheader_params = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\npost_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def __call_api(\n            self, resource_path, method, path_params=None,\n            query_params=None, header_params=None, body=None, post_params=None,\n            files=None, response_type=None, auth_settings=None,\n            _return_http_data_only=None, collection_formats=None,\n            _preload_content=True, _request_timeout=None, _host=None):\n    \n        config = self.configuration\n    \n        # header parameters\n        header_params = header_params or {}\n        header_params.update(self.default_headers)\n        if self.cookie:\n            header_params['Cookie'] = self.cookie\n        if header_params:\n            header_params = self.sanitize_for_serialization(header_params)\n            header_params = dict(self.parameters_to_tuples(header_params,\n                                                           collection_formats))\n    \n        # path parameters\n        if path_params:\n            path_params = self.sanitize_for_serialization(path_params)\n            path_params = self.parameters_to_tuples(path_params,\n                                                    collection_formats)\n            for k, v in path_params:\n                # specified safe chars, encode everything\n                resource_path = resource_path.replace(\n                    '{%s}' % k,\n                    quote(str(v), safe=config.safe_chars_for_path_param)\n                )\n    \n        # query parameters\n        if query_params:\n            query_params = self.sanitize_for_serialization(query_params)\n            query_params = self.parameters_to_tuples(query_params,\n                                                     collection_formats)\n    \n        # post parameters\n        if post_params or files:\n            post_params = post_params if post_params else []\n            post_params = self.sanitize_for_serialization(post_params)\n            post_params = self.parameters_to_tuples(post_params,\n                                                    collection_formats)\n            post_params.extend(self.files_parameters(files))\n    \n        # auth setting\n        self.update_params_for_auth(header_params, query_params, auth_settings)\n    \n        # body\n        if body:\n            body = self.sanitize_for_serialization(body)\n    \n        # request url\n        if _host is None:\n            url = self.configuration.host + resource_path\n        else:\n            # use server/host defined in path or operation instead\n            url = _host + resource_path\n    \n        # perform request and return response\n>       response_data = self.request(\n            method, url, query_params=query_params, headers=header_params,\n            post_params=post_params, body=body,\n            _preload_content=_preload_content,\n            _request_timeout=_request_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:180: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202144d90>\nmethod = 'POST'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-62876e81/llminferenceserviceconfigs'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\npost_params = []\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\n_preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                post_params=None, body=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Makes the HTTP request using RESTClient.\"\"\"\n        if method == \"GET\":\n            return self.rest_client.GET(url,\n                                        query_params=query_params,\n                                        _preload_content=_preload_content,\n                                        _request_timeout=_request_timeout,\n                                        headers=headers)\n        elif method == \"HEAD\":\n            return self.rest_client.HEAD(url,\n                                         query_params=query_params,\n                                         _preload_content=_preload_content,\n                                         _request_timeout=_request_timeout,\n                                         headers=headers)\n        elif method == \"OPTIONS\":\n            return self.rest_client.OPTIONS(url,\n                                            query_params=query_params,\n                                            headers=headers,\n                                            _preload_content=_preload_content,\n                                            _request_timeout=_request_timeout)\n        elif method == \"POST\":\n>           return self.rest_client.POST(url,\n                                         query_params=query_params,\n                                         headers=headers,\n                                         post_params=post_params,\n                                         _preload_content=_preload_content,\n                                         _request_timeout=_request_timeout,\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:391: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc202147a50>\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-62876e81/llminferenceserviceconfigs'\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nquery_params = [], post_params = []\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\n_preload_content = True, _request_timeout = None\n\n    def POST(self, url, headers=None, query_params=None, post_params=None,\n             body=None, _preload_content=True, _request_timeout=None):\n>       return self.request(\"POST\", url,\n                            headers=headers,\n                            query_params=query_params,\n                            post_params=post_params,\n                            _preload_content=_preload_content,\n                            _request_timeout=_request_timeout,\n                            body=body)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:279: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc202147a50>\nmethod = 'POST'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-62876e81/llminferenceserviceconfigs'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-managed...rvice-62876e81'}, 'spec': {'router': {'gateway': {}, 'route': {}, 'scheduler': {'template': {'containers': [{...}]}}}}}\npost_params = {}, _preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                body=None, post_params=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Perform requests.\n    \n        :param method: http request method\n        :param url: http request url\n        :param query_params: query parameters in the url\n        :param headers: http request headers\n        :param body: request json body, for `application/json`\n        :param post_params: request post parameters,\n                            `application/x-www-form-urlencoded`\n                            and `multipart/form-data`\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        \"\"\"\n        method = method.upper()\n        assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',\n                          'PATCH', 'OPTIONS']\n    \n        if post_params and body:\n            raise ApiValueError(\n                \"body parameter cannot be used with post_params parameter.\"\n            )\n    \n        post_params = post_params or {}\n        headers = headers or {}\n    \n        timeout = None\n        if _request_timeout:\n            if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)):  # noqa: E501,F821\n                timeout = urllib3.Timeout(total=_request_timeout)\n            elif (isinstance(_request_timeout, tuple) and\n                  len(_request_timeout) == 2):\n                timeout = urllib3.Timeout(\n                    connect=_request_timeout[0], read=_request_timeout[1])\n    \n        if 'Content-Type' not in headers:\n            headers['Content-Type'] = 'application/json'\n    \n        try:\n            # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`\n            if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:\n                if query_params:\n                    url += '?' + urlencode(query_params)\n                if (re.search('json', headers['Content-Type'], re.IGNORECASE) or\n                        headers['Content-Type'] == 'application/apply-patch+yaml'):\n                    if headers['Content-Type'] == 'application/json-patch+json':\n                        if not isinstance(body, list):\n                            headers['Content-Type'] = \\\n                                'application/strategic-merge-patch+json'\n                    request_body = None\n                    if body is not None:\n                        request_body = json.dumps(body)\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'application/x-www-form-urlencoded':  # noqa: E501\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=False,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'multipart/form-data':\n                    # must del headers['Content-Type'], or the correct\n                    # Content-Type which generated by urllib3 will be\n                    # overwritten.\n                    del headers['Content-Type']\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=True,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                # Pass a `string` parameter directly in the body to support\n                # other content types than Json when `body` argument is\n                # provided in serialized form\n                elif isinstance(body, str) or isinstance(body, bytes):\n                    request_body = body\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                else:\n                    # Cannot generate the request from given parameters\n                    msg = \"\"\"Cannot prepare a request message for provided\n                             arguments. Please check that your arguments match\n                             declared content type.\"\"\"\n                    raise ApiException(status=0, reason=msg)\n            # For `GET`, `HEAD`\n            else:\n                r = self.pool_manager.request(method, url,\n                                              fields=query_params,\n                                              preload_content=_preload_content,\n                                              timeout=timeout,\n                                              headers=headers)\n        except urllib3.exceptions.SSLError as e:\n            msg = \"{0}\\n{1}\".format(type(e).__name__, str(e))\n            raise ApiException(status=0, reason=msg)\n    \n        if _preload_content:\n            r = RESTResponse(r)\n    \n            # In the python 3, the response.data is bytes.\n            # we need to decode it to string.\n            if six.PY3:\n                r.data = r.data.decode('utf8')\n    \n            # log response body\n            logger.debug(\"response body: %s\", r.data)\n    \n        if not 200 <= r.status <= 299:\n>           raise ApiException(http_resp=r)\nE           kubernetes.client.exceptions.ApiException: (500)\nE           Reason: Internal Server Error\nE           HTTP response headers: HTTPHeaderDict({'Audit-Id': '4b3f3cac-d2e3-4b14-beb8-d3bea22125be', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:06 GMT', 'Content-Length': '701'})\nE           HTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Internal error occurred: failed calling webhook \\\"llminferenceserviceconfig.kserve-webhook-server.v1alpha1.validator\\\": failed to call webhook: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/validate-serving-kserve-io-v1alpha1-llminferenceserviceconfig?timeout=10s\\\": EOF\",\"reason\":\"InternalError\",\"details\":{\"causes\":[{\"message\":\"failed calling webhook \\\"llminferenceserviceconfig.kserve-webhook-server.v1alpha1.validator\\\": failed to call webhook: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/validate-serving-kserve-io-v1alpha1-llminferenceserviceconfig?timeout=10s\\\": EOF\"}]},\"code\":500}\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:238: ApiException"}, "teardown": {"duration": 0.0005258700002741534, "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": 242, "outcome": "error", "keywords": ["test_llm_inference_service[router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]", "parametrize", "asyncio", "cluster_cpu", "cluster_single_node", "__wrapped__", "pytestmark", "router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m", "llminferenceservice", "llmisvc_core", "test_llm_inference_service.py", "llmisvc/__init__.py", "e2e"], "setup": {"duration": 0.19856739600072615, "outcome": "failed", "crash": {"path": "/workspace/source/python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py", "lineno": 238, "message": "kubernetes.client.exceptions.ApiException: (500)\nReason: Internal Server Error\nHTTP response headers: HTTPHeaderDict({'Audit-Id': 'ec254936-5f14-42fa-86e9-bae4267dd9cf', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:07 GMT', 'Content-Length': '701'})\nHTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Internal error occurred: failed calling webhook \\\"llminferenceserviceconfig.kserve-webhook-server.v1alpha1.validator\\\": failed to call webhook: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/validate-serving-kserve-io-v1alpha1-llminferenceserviceconfig?timeout=10s\\\": EOF\",\"reason\":\"InternalError\",\"details\":{\"causes\":[{\"message\":\"failed calling webhook \\\"llminferenceserviceconfig.kserve-webhook-server.v1alpha1.validator\\\": failed to call webhook: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/validate-serving-kserve-io-v1alpha1-llminferenceserviceconfig?timeout=10s\\\": EOF\"}]},\"code\":500}"}, "traceback": [{"path": "common/gateway_proxy_istio.py", "lineno": 183, "message": ""}, {"path": "llmisvc/fixtures.py", "lineno": 1611, "message": ""}, {"path": "llmisvc/fixtures.py", "lineno": 1573, "message": ""}, {"path": "llmisvc/fixtures.py", "lineno": 1747, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py", "lineno": 231, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py", "lineno": 354, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py", "lineno": 348, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py", "lineno": 180, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py", "lineno": 391, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py", "lineno": 279, "message": ""}, {"path": "../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py", "lineno": 238, "message": "ApiException"}], "longrepr": "[gw1] linux -- Python 3.11.13 /workspace/source/python/kserve/.venv/bin/python\n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7fc201e70610>\nllm_config = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\nnamespace = 'e2e-test-llm-inference-service-d73d44f4'\n\n    def _create_or_update_llmisvc_config(kserve_client, llm_config, namespace=None):\n        \"\"\"Create or update an LLMInferenceServiceConfig resource.\"\"\"\n        version = llm_config[\"apiVersion\"].split(\"/\")[1]\n    \n        if namespace is None:\n            namespace = llm_config.get(\"metadata\", {}).get(\"namespace\", \"default\")\n    \n        name = llm_config.get(\"metadata\", {}).get(\"name\")\n        if not name:\n            raise ValueError(\"LLMInferenceServiceConfig must have a name in metadata\")\n    \n        logger.info(f\"Checking LLMInferenceServiceConfig {name} in namespace {namespace}\")\n    \n        try:\n>           existing_config = kserve_client.api_instance.get_namespaced_custom_object(\n                constants.KSERVE_GROUP,\n                version,\n                namespace,\n                KSERVE_PLURAL_LLMINFERENCESERVICECONFIG,\n                name,\n            )\n\nllmisvc/fixtures.py:1721: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc202133e10>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-d73d44f4'\nplural = 'llminferenceserviceconfigs'\nname = 'router-custom-route-timeout-pd-8b408578'\nkwargs = {'_return_http_data_only': True}\n\n    def get_namespaced_custom_object(self, group, version, namespace, plural, name, **kwargs):  # noqa: E501\n        \"\"\"get_namespaced_custom_object  # noqa: E501\n    \n        Returns a namespace scoped custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.get_namespaced_custom_object(group, version, namespace, plural, name, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: the custom resource's group (required)\n        :param str version: the custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: the custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param str name: the custom object's name (required)\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: object\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n        kwargs['_return_http_data_only'] = True\n>       return self.get_namespaced_custom_object_with_http_info(group, version, namespace, plural, name, **kwargs)  # noqa: E501\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:1632: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc202133e10>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-d73d44f4'\nplural = 'llminferenceserviceconfigs'\nname = 'router-custom-route-timeout-pd-8b408578'\nkwargs = {'_return_http_data_only': True}\nlocal_var_params = {'_return_http_data_only': True, 'all_params': ['group', 'version', 'namespace', 'plural', 'name', 'async_req', ...], 'auth_settings': ['BearerToken'], 'body_params': None, ...}\nall_params = ['group', 'version', 'namespace', 'plural', 'name', 'async_req', ...]\nkey = '_return_http_data_only', val = True, collection_formats = {}\npath_params = {'group': 'serving.kserve.io', 'name': 'router-custom-route-timeout-pd-8b408578', 'namespace': 'e2e-test-llm-inference-service-d73d44f4', 'plural': 'llminferenceserviceconfigs', ...}\nquery_params = []\n\n    def get_namespaced_custom_object_with_http_info(self, group, version, namespace, plural, name, **kwargs):  # noqa: E501\n        \"\"\"get_namespaced_custom_object  # noqa: E501\n    \n        Returns a namespace scoped custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.get_namespaced_custom_object_with_http_info(group, version, namespace, plural, name, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: the custom resource's group (required)\n        :param str version: the custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: the custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param str name: the custom object's name (required)\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: tuple(object, status_code(int), headers(HTTPHeaderDict))\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n    \n        local_var_params = locals()\n    \n        all_params = [\n            'group',\n            'version',\n            'namespace',\n            'plural',\n            'name'\n        ]\n        all_params.extend(\n            [\n                'async_req',\n                '_return_http_data_only',\n                '_preload_content',\n                '_request_timeout'\n            ]\n        )\n    \n        for key, val in six.iteritems(local_var_params['kwargs']):\n            if key not in all_params:\n                raise ApiTypeError(\n                    \"Got an unexpected keyword argument '%s'\"\n                    \" to method get_namespaced_custom_object\" % key\n                )\n            local_var_params[key] = val\n        del local_var_params['kwargs']\n        # verify the required parameter 'group' is set\n        if self.api_client.client_side_validation and ('group' not in local_var_params or  # noqa: E501\n                                                        local_var_params['group'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `group` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'version' is set\n        if self.api_client.client_side_validation and ('version' not in local_var_params or  # noqa: E501\n                                                        local_var_params['version'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `version` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'namespace' is set\n        if self.api_client.client_side_validation and ('namespace' not in local_var_params or  # noqa: E501\n                                                        local_var_params['namespace'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `namespace` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'plural' is set\n        if self.api_client.client_side_validation and ('plural' not in local_var_params or  # noqa: E501\n                                                        local_var_params['plural'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `plural` when calling `get_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'name' is set\n        if self.api_client.client_side_validation and ('name' not in local_var_params or  # noqa: E501\n                                                        local_var_params['name'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `name` when calling `get_namespaced_custom_object`\")  # noqa: E501\n    \n        collection_formats = {}\n    \n        path_params = {}\n        if 'group' in local_var_params:\n            path_params['group'] = local_var_params['group']  # noqa: E501\n        if 'version' in local_var_params:\n            path_params['version'] = local_var_params['version']  # noqa: E501\n        if 'namespace' in local_var_params:\n            path_params['namespace'] = local_var_params['namespace']  # noqa: E501\n        if 'plural' in local_var_params:\n            path_params['plural'] = local_var_params['plural']  # noqa: E501\n        if 'name' in local_var_params:\n            path_params['name'] = local_var_params['name']  # noqa: E501\n    \n        query_params = []\n    \n        header_params = {}\n    \n        form_params = []\n        local_var_files = {}\n    \n        body_params = None\n        # HTTP header `Accept`\n        header_params['Accept'] = self.api_client.select_header_accept(\n            ['application/json'])  # noqa: E501\n    \n        # Authentication setting\n        auth_settings = ['BearerToken']  # noqa: E501\n    \n>       return self.api_client.call_api(\n            '/apis/{group}/{version}/namespaces/{namespace}/{plural}/{name}', 'GET',\n            path_params,\n            query_params,\n            header_params,\n            body=body_params,\n            post_params=form_params,\n            files=local_var_files,\n            response_type='object',  # noqa: E501\n            auth_settings=auth_settings,\n            async_req=local_var_params.get('async_req'),\n            _return_http_data_only=local_var_params.get('_return_http_data_only'),  # noqa: E501\n            _preload_content=local_var_params.get('_preload_content', True),\n            _request_timeout=local_var_params.get('_request_timeout'),\n            collection_formats=collection_formats)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:1739: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202133dd0>\nresource_path = '/apis/{group}/{version}/namespaces/{namespace}/{plural}/{name}'\nmethod = 'GET'\npath_params = {'group': 'serving.kserve.io', 'name': 'router-custom-route-timeout-pd-8b408578', 'namespace': 'e2e-test-llm-inference-service-d73d44f4', 'plural': 'llminferenceserviceconfigs', ...}\nquery_params = []\nheader_params = {'Accept': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], async_req = None, _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def call_api(self, resource_path, method,\n                 path_params=None, query_params=None, header_params=None,\n                 body=None, post_params=None, files=None,\n                 response_type=None, auth_settings=None, async_req=None,\n                 _return_http_data_only=None, collection_formats=None,\n                 _preload_content=True, _request_timeout=None, _host=None):\n        \"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\n    \n        To make an async_req request, set the async_req parameter.\n    \n        :param resource_path: Path to method endpoint.\n        :param method: Method to call.\n        :param path_params: Path parameters in the url.\n        :param query_params: Query parameters in the url.\n        :param header_params: Header parameters to be\n            placed in the request header.\n        :param body: Request body.\n        :param post_params dict: Request post form parameters,\n            for `application/x-www-form-urlencoded`, `multipart/form-data`.\n        :param auth_settings list: Auth Settings names for the request.\n        :param response: Response data type.\n        :param files dict: key -> filename, value -> filepath,\n            for `multipart/form-data`.\n        :param async_req bool: execute request asynchronously\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param collection_formats: dict of collection formats for path, query,\n            header, and post parameters.\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return:\n            If async_req parameter is True,\n            the request will be called asynchronously.\n            The method will return the request thread.\n            If parameter async_req is False or missing,\n            then the method will return the response directly.\n        \"\"\"\n        if not async_req:\n>           return self.__call_api(resource_path, method,\n                                   path_params, query_params, header_params,\n                                   body, post_params, files,\n                                   response_type, auth_settings,\n                                   _return_http_data_only, collection_formats,\n                                   _preload_content, _request_timeout, _host)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:348: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202133dd0>\nresource_path = '/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-d73d44f4/llminferenceserviceconfigs/router-custom-route-timeout-pd-8b408578'\nmethod = 'GET'\npath_params = [('group', 'serving.kserve.io'), ('version', 'v1alpha1'), ('namespace', 'e2e-test-llm-inference-service-d73d44f4'), ('plural', 'llminferenceserviceconfigs'), ('name', 'router-custom-route-timeout-pd-8b408578')]\nquery_params = []\nheader_params = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def __call_api(\n            self, resource_path, method, path_params=None,\n            query_params=None, header_params=None, body=None, post_params=None,\n            files=None, response_type=None, auth_settings=None,\n            _return_http_data_only=None, collection_formats=None,\n            _preload_content=True, _request_timeout=None, _host=None):\n    \n        config = self.configuration\n    \n        # header parameters\n        header_params = header_params or {}\n        header_params.update(self.default_headers)\n        if self.cookie:\n            header_params['Cookie'] = self.cookie\n        if header_params:\n            header_params = self.sanitize_for_serialization(header_params)\n            header_params = dict(self.parameters_to_tuples(header_params,\n                                                           collection_formats))\n    \n        # path parameters\n        if path_params:\n            path_params = self.sanitize_for_serialization(path_params)\n            path_params = self.parameters_to_tuples(path_params,\n                                                    collection_formats)\n            for k, v in path_params:\n                # specified safe chars, encode everything\n                resource_path = resource_path.replace(\n                    '{%s}' % k,\n                    quote(str(v), safe=config.safe_chars_for_path_param)\n                )\n    \n        # query parameters\n        if query_params:\n            query_params = self.sanitize_for_serialization(query_params)\n            query_params = self.parameters_to_tuples(query_params,\n                                                     collection_formats)\n    \n        # post parameters\n        if post_params or files:\n            post_params = post_params if post_params else []\n            post_params = self.sanitize_for_serialization(post_params)\n            post_params = self.parameters_to_tuples(post_params,\n                                                    collection_formats)\n            post_params.extend(self.files_parameters(files))\n    \n        # auth setting\n        self.update_params_for_auth(header_params, query_params, auth_settings)\n    \n        # body\n        if body:\n            body = self.sanitize_for_serialization(body)\n    \n        # request url\n        if _host is None:\n            url = self.configuration.host + resource_path\n        else:\n            # use server/host defined in path or operation instead\n            url = _host + resource_path\n    \n        # perform request and return response\n>       response_data = self.request(\n            method, url, query_params=query_params, headers=header_params,\n            post_params=post_params, body=body,\n            _preload_content=_preload_content,\n            _request_timeout=_request_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:180: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202133dd0>\nmethod = 'GET'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1a.../namespaces/e2e-test-llm-inference-service-d73d44f4/llminferenceserviceconfigs/router-custom-route-timeout-pd-8b408578'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\npost_params = [], body = None, _preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                post_params=None, body=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Makes the HTTP request using RESTClient.\"\"\"\n        if method == \"GET\":\n>           return self.rest_client.GET(url,\n                                        query_params=query_params,\n                                        _preload_content=_preload_content,\n                                        _request_timeout=_request_timeout,\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:373: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc202133e50>\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1a.../namespaces/e2e-test-llm-inference-service-d73d44f4/llminferenceserviceconfigs/router-custom-route-timeout-pd-8b408578'\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nquery_params = [], _preload_content = True, _request_timeout = None\n\n    def GET(self, url, headers=None, query_params=None, _preload_content=True,\n            _request_timeout=None):\n>       return self.request(\"GET\", url,\n                            headers=headers,\n                            _preload_content=_preload_content,\n                            _request_timeout=_request_timeout,\n                            query_params=query_params)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:244: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc202133e50>\nmethod = 'GET'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1a.../namespaces/e2e-test-llm-inference-service-d73d44f4/llminferenceserviceconfigs/router-custom-route-timeout-pd-8b408578'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = None, post_params = {}, _preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                body=None, post_params=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Perform requests.\n    \n        :param method: http request method\n        :param url: http request url\n        :param query_params: query parameters in the url\n        :param headers: http request headers\n        :param body: request json body, for `application/json`\n        :param post_params: request post parameters,\n                            `application/x-www-form-urlencoded`\n                            and `multipart/form-data`\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        \"\"\"\n        method = method.upper()\n        assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',\n                          'PATCH', 'OPTIONS']\n    \n        if post_params and body:\n            raise ApiValueError(\n                \"body parameter cannot be used with post_params parameter.\"\n            )\n    \n        post_params = post_params or {}\n        headers = headers or {}\n    \n        timeout = None\n        if _request_timeout:\n            if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)):  # noqa: E501,F821\n                timeout = urllib3.Timeout(total=_request_timeout)\n            elif (isinstance(_request_timeout, tuple) and\n                  len(_request_timeout) == 2):\n                timeout = urllib3.Timeout(\n                    connect=_request_timeout[0], read=_request_timeout[1])\n    \n        if 'Content-Type' not in headers:\n            headers['Content-Type'] = 'application/json'\n    \n        try:\n            # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`\n            if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:\n                if query_params:\n                    url += '?' + urlencode(query_params)\n                if (re.search('json', headers['Content-Type'], re.IGNORECASE) or\n                        headers['Content-Type'] == 'application/apply-patch+yaml'):\n                    if headers['Content-Type'] == 'application/json-patch+json':\n                        if not isinstance(body, list):\n                            headers['Content-Type'] = \\\n                                'application/strategic-merge-patch+json'\n                    request_body = None\n                    if body is not None:\n                        request_body = json.dumps(body)\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'application/x-www-form-urlencoded':  # noqa: E501\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=False,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'multipart/form-data':\n                    # must del headers['Content-Type'], or the correct\n                    # Content-Type which generated by urllib3 will be\n                    # overwritten.\n                    del headers['Content-Type']\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=True,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                # Pass a `string` parameter directly in the body to support\n                # other content types than Json when `body` argument is\n                # provided in serialized form\n                elif isinstance(body, str) or isinstance(body, bytes):\n                    request_body = body\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                else:\n                    # Cannot generate the request from given parameters\n                    msg = \"\"\"Cannot prepare a request message for provided\n                             arguments. Please check that your arguments match\n                             declared content type.\"\"\"\n                    raise ApiException(status=0, reason=msg)\n            # For `GET`, `HEAD`\n            else:\n                r = self.pool_manager.request(method, url,\n                                              fields=query_params,\n                                              preload_content=_preload_content,\n                                              timeout=timeout,\n                                              headers=headers)\n        except urllib3.exceptions.SSLError as e:\n            msg = \"{0}\\n{1}\".format(type(e).__name__, str(e))\n            raise ApiException(status=0, reason=msg)\n    \n        if _preload_content:\n            r = RESTResponse(r)\n    \n            # In the python 3, the response.data is bytes.\n            # we need to decode it to string.\n            if six.PY3:\n                r.data = r.data.decode('utf8')\n    \n            # log response body\n            logger.debug(\"response body: %s\", r.data)\n    \n        if not 200 <= r.status <= 299:\n>           raise ApiException(http_resp=r)\nE           kubernetes.client.exceptions.ApiException: (404)\nE           Reason: Not Found\nE           HTTP response headers: HTTPHeaderDict({'Audit-Id': '3e266d16-7bda-4ce7-b797-479ff8586efd', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:07 GMT', 'Content-Length': '336'})\nE           HTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"llminferenceserviceconfigs.serving.kserve.io \\\"router-custom-route-timeout-pd-8b408578\\\" not found\",\"reason\":\"NotFound\",\"details\":{\"name\":\"router-custom-route-timeout-pd-8b408578\",\"group\":\"serving.kserve.io\",\"kind\":\"llminferenceserviceconfigs\"},\"code\":404}\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:238: ApiException\n\nDuring handling of the above exception, another exception occurred:\n\nrequest = <SubRequest 'ensure_gateway_proxy_memory' for <Function test_llm_inference_service[router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]>>\n\n    @pytest.fixture(autouse=True)\n    def ensure_gateway_proxy_memory(request):\n        \"\"\"After test setup creates gateways, patch them for proxy memory.\"\"\"\n        if not GATEWAY_PROXY_MEMORY:\n            return\n    \n        # Let test_case (llmisvc) create gateways first\n    \n        if \"test_case\" in request.fixturenames:\n>           request.getfixturevalue(\"test_case\")\n\ncommon/gateway_proxy_istio.py:183: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nrequest = <SubRequest 'test_case' for <Function test_llm_inference_service[router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]>>\ntest_namespace = 'e2e-test-llm-inference-service-d73d44f4'\n\n    @pytest.fixture(scope=\"function\")\n    def test_case(request, test_namespace):\n        tc = request.param\n        ns = test_namespace\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        tc.namespace = ns\n        for peer in tc.peers:\n            peer.namespace = ns\n    \n        for func in tc.before_test:\n            func(tc)\n    \n>       _setup_test_case_service(kserve_client, tc, request.node.name, namespace=ns)\n\nllmisvc/fixtures.py:1611: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7fc201e70610>\ntc = TestCase(base_refs=['router-custom-route-timeout-pd', 'scheduler-managed', 'workload-pd-cpu', 'model-fb-opt-125m'], pr...inference-service-d73d44f4', before_test=[], after_test=[], peers=[], llm_service=None, model_name='facebook/opt-125m')\ntest_node_name = 'test_llm_inference_service[router-custom-route-timeout-pd-scheduler-managed-workload-pd-cpu-model-fb-opt-125m]'\nnamespace = 'e2e-test-llm-inference-service-d73d44f4', peer_index = None\n\n    def _setup_test_case_service(\n        kserve_client, tc, test_node_name, namespace, peer_index=None\n    ):\n        \"\"\"Create LLMInferenceServiceConfigs and build the LLMInferenceService for a TestCase.\n    \n        Returns a list of created config names for cleanup tracking.\n        \"\"\"\n        missing_refs = [\n            ref for ref in tc.base_refs if ref not in LLMINFERENCESERVICE_CONFIGS\n        ]\n        if missing_refs:\n            raise ValueError(\n                f\"Missing base_refs in LLMINFERENCESERVICE_CONFIGS: {missing_refs}\"\n            )\n        if not tc.service_name:\n            suffix = f\"-peer-{peer_index}\" if peer_index is not None else \"\"\n            tc.service_name = generate_service_name(test_node_name + suffix, tc.base_refs)\n        if tc.model_name == \"default/model\":\n            tc.model_name = _get_model_name_from_configs(tc.base_refs)\n        elif \"{namespace}\" in tc.model_name:\n            tc.model_name = tc.model_name.format(namespace=namespace)\n    \n        created_configs = []\n        unique_base_refs = []\n        for base_ref in tc.base_refs:\n            unique_config_name = generate_k8s_safe_suffix(base_ref, [tc.service_name])\n            unique_base_refs.append(unique_config_name)\n    \n            config = LLMINFERENCESERVICE_CONFIGS[base_ref]\n            spec = config(namespace) if callable(config) else copy.deepcopy(config)\n    \n            unique_config_body = {\n                \"apiVersion\": \"serving.kserve.io/v1alpha1\",\n                \"kind\": \"LLMInferenceServiceConfig\",\n                \"metadata\": {\n                    \"name\": unique_config_name,\n                    \"namespace\": namespace,\n                },\n                \"spec\": spec,\n            }\n    \n>           _create_or_update_llmisvc_config(kserve_client, unique_config_body, namespace)\n\nllmisvc/fixtures.py:1573: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nkserve_client = <kserve.api.kserve_client.KServeClient object at 0x7fc201e70610>\nllm_config = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\nnamespace = 'e2e-test-llm-inference-service-d73d44f4'\n\n    def _create_or_update_llmisvc_config(kserve_client, llm_config, namespace=None):\n        \"\"\"Create or update an LLMInferenceServiceConfig resource.\"\"\"\n        version = llm_config[\"apiVersion\"].split(\"/\")[1]\n    \n        if namespace is None:\n            namespace = llm_config.get(\"metadata\", {}).get(\"namespace\", \"default\")\n    \n        name = llm_config.get(\"metadata\", {}).get(\"name\")\n        if not name:\n            raise ValueError(\"LLMInferenceServiceConfig must have a name in metadata\")\n    \n        logger.info(f\"Checking LLMInferenceServiceConfig {name} in namespace {namespace}\")\n    \n        try:\n            existing_config = kserve_client.api_instance.get_namespaced_custom_object(\n                constants.KSERVE_GROUP,\n                version,\n                namespace,\n                KSERVE_PLURAL_LLMINFERENCESERVICECONFIG,\n                name,\n            )\n    \n            llm_config[\"metadata\"] = existing_config[\"metadata\"]\n    \n            outputs = kserve_client.api_instance.replace_namespaced_custom_object(\n                constants.KSERVE_GROUP,\n                version,\n                namespace,\n                KSERVE_PLURAL_LLMINFERENCESERVICECONFIG,\n                name,\n                llm_config,\n            )\n            logger.info(f\"\u2713 Successfully updated LLMInferenceServiceConfig {name}\")\n            return outputs\n    \n        except client.rest.ApiException as e:\n            if e.status == 404:  # Not found - create it\n                logger.info(\n                    f\"Resource not found, creating LLMInferenceServiceConfig {name}\"\n                )\n>               outputs = kserve_client.api_instance.create_namespaced_custom_object(\n                    constants.KSERVE_GROUP,\n                    version,\n                    namespace,\n                    KSERVE_PLURAL_LLMINFERENCESERVICECONFIG,\n                    llm_config,\n                )\n\nllmisvc/fixtures.py:1747: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc202133e10>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-d73d44f4'\nplural = 'llminferenceserviceconfigs'\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\nkwargs = {'_return_http_data_only': True}\n\n    def create_namespaced_custom_object(self, group, version, namespace, plural, body, **kwargs):  # noqa: E501\n        \"\"\"create_namespaced_custom_object  # noqa: E501\n    \n        Creates a namespace scoped Custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.create_namespaced_custom_object(group, version, namespace, plural, body, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: The custom resource's group name (required)\n        :param str version: The custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: The custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param object body: The JSON schema of the Resource to create. (required)\n        :param str pretty: If 'true', then the output is pretty printed.\n        :param str dry_run: When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed\n        :param str field_manager: fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.\n        :param str field_validation: fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. (optional)\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: object\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n        kwargs['_return_http_data_only'] = True\n>       return self.create_namespaced_custom_object_with_http_info(group, version, namespace, plural, body, **kwargs)  # noqa: E501\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:231: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api.custom_objects_api.CustomObjectsApi object at 0x7fc202133e10>\ngroup = 'serving.kserve.io', version = 'v1alpha1'\nnamespace = 'e2e-test-llm-inference-service-d73d44f4'\nplural = 'llminferenceserviceconfigs'\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\nkwargs = {'_return_http_data_only': True}\nlocal_var_params = {'_return_http_data_only': True, 'all_params': ['group', 'version', 'namespace', 'plural', 'body', 'pretty', ...], 'au...e-test-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {...}}}}}}, ...}\nall_params = ['group', 'version', 'namespace', 'plural', 'body', 'pretty', ...]\nkey = '_return_http_data_only', val = True, collection_formats = {}\npath_params = {'group': 'serving.kserve.io', 'namespace': 'e2e-test-llm-inference-service-d73d44f4', 'plural': 'llminferenceserviceconfigs', 'version': 'v1alpha1'}\nquery_params = []\n\n    def create_namespaced_custom_object_with_http_info(self, group, version, namespace, plural, body, **kwargs):  # noqa: E501\n        \"\"\"create_namespaced_custom_object  # noqa: E501\n    \n        Creates a namespace scoped Custom object  # noqa: E501\n        This method makes a synchronous HTTP request by default. To make an\n        asynchronous HTTP request, please pass async_req=True\n        >>> thread = api.create_namespaced_custom_object_with_http_info(group, version, namespace, plural, body, async_req=True)\n        >>> result = thread.get()\n    \n        :param async_req bool: execute request asynchronously\n        :param str group: The custom resource's group name (required)\n        :param str version: The custom resource's version (required)\n        :param str namespace: The custom resource's namespace (required)\n        :param str plural: The custom resource's plural name. For TPRs this would be lowercase plural kind. (required)\n        :param object body: The JSON schema of the Resource to create. (required)\n        :param str pretty: If 'true', then the output is pretty printed.\n        :param str dry_run: When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed\n        :param str field_manager: fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.\n        :param str field_validation: fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. (optional)\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return: tuple(object, status_code(int), headers(HTTPHeaderDict))\n                 If the method is called asynchronously,\n                 returns the request thread.\n        \"\"\"\n    \n        local_var_params = locals()\n    \n        all_params = [\n            'group',\n            'version',\n            'namespace',\n            'plural',\n            'body',\n            'pretty',\n            'dry_run',\n            'field_manager',\n            'field_validation'\n        ]\n        all_params.extend(\n            [\n                'async_req',\n                '_return_http_data_only',\n                '_preload_content',\n                '_request_timeout'\n            ]\n        )\n    \n        for key, val in six.iteritems(local_var_params['kwargs']):\n            if key not in all_params:\n                raise ApiTypeError(\n                    \"Got an unexpected keyword argument '%s'\"\n                    \" to method create_namespaced_custom_object\" % key\n                )\n            local_var_params[key] = val\n        del local_var_params['kwargs']\n        # verify the required parameter 'group' is set\n        if self.api_client.client_side_validation and ('group' not in local_var_params or  # noqa: E501\n                                                        local_var_params['group'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `group` when calling `create_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'version' is set\n        if self.api_client.client_side_validation and ('version' not in local_var_params or  # noqa: E501\n                                                        local_var_params['version'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `version` when calling `create_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'namespace' is set\n        if self.api_client.client_side_validation and ('namespace' not in local_var_params or  # noqa: E501\n                                                        local_var_params['namespace'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `namespace` when calling `create_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'plural' is set\n        if self.api_client.client_side_validation and ('plural' not in local_var_params or  # noqa: E501\n                                                        local_var_params['plural'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `plural` when calling `create_namespaced_custom_object`\")  # noqa: E501\n        # verify the required parameter 'body' is set\n        if self.api_client.client_side_validation and ('body' not in local_var_params or  # noqa: E501\n                                                        local_var_params['body'] is None):  # noqa: E501\n            raise ApiValueError(\"Missing the required parameter `body` when calling `create_namespaced_custom_object`\")  # noqa: E501\n    \n        collection_formats = {}\n    \n        path_params = {}\n        if 'group' in local_var_params:\n            path_params['group'] = local_var_params['group']  # noqa: E501\n        if 'version' in local_var_params:\n            path_params['version'] = local_var_params['version']  # noqa: E501\n        if 'namespace' in local_var_params:\n            path_params['namespace'] = local_var_params['namespace']  # noqa: E501\n        if 'plural' in local_var_params:\n            path_params['plural'] = local_var_params['plural']  # noqa: E501\n    \n        query_params = []\n        if 'pretty' in local_var_params and local_var_params['pretty'] is not None:  # noqa: E501\n            query_params.append(('pretty', local_var_params['pretty']))  # noqa: E501\n        if 'dry_run' in local_var_params and local_var_params['dry_run'] is not None:  # noqa: E501\n            query_params.append(('dryRun', local_var_params['dry_run']))  # noqa: E501\n        if 'field_manager' in local_var_params and local_var_params['field_manager'] is not None:  # noqa: E501\n            query_params.append(('fieldManager', local_var_params['field_manager']))  # noqa: E501\n        if 'field_validation' in local_var_params and local_var_params['field_validation'] is not None:  # noqa: E501\n            query_params.append(('fieldValidation', local_var_params['field_validation']))  # noqa: E501\n    \n        header_params = {}\n    \n        form_params = []\n        local_var_files = {}\n    \n        body_params = None\n        if 'body' in local_var_params:\n            body_params = local_var_params['body']\n        # HTTP header `Accept`\n        header_params['Accept'] = self.api_client.select_header_accept(\n            ['application/json'])  # noqa: E501\n    \n        # Authentication setting\n        auth_settings = ['BearerToken']  # noqa: E501\n    \n>       return self.api_client.call_api(\n            '/apis/{group}/{version}/namespaces/{namespace}/{plural}', 'POST',\n            path_params,\n            query_params,\n            header_params,\n            body=body_params,\n            post_params=form_params,\n            files=local_var_files,\n            response_type='object',  # noqa: E501\n            auth_settings=auth_settings,\n            async_req=local_var_params.get('async_req'),\n            _return_http_data_only=local_var_params.get('_return_http_data_only'),  # noqa: E501\n            _preload_content=local_var_params.get('_preload_content', True),\n            _request_timeout=local_var_params.get('_request_timeout'),\n            collection_formats=collection_formats)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api/custom_objects_api.py:354: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202133dd0>\nresource_path = '/apis/{group}/{version}/namespaces/{namespace}/{plural}'\nmethod = 'POST'\npath_params = {'group': 'serving.kserve.io', 'namespace': 'e2e-test-llm-inference-service-d73d44f4', 'plural': 'llminferenceserviceconfigs', 'version': 'v1alpha1'}\nquery_params = []\nheader_params = {'Accept': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\npost_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], async_req = None, _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def call_api(self, resource_path, method,\n                 path_params=None, query_params=None, header_params=None,\n                 body=None, post_params=None, files=None,\n                 response_type=None, auth_settings=None, async_req=None,\n                 _return_http_data_only=None, collection_formats=None,\n                 _preload_content=True, _request_timeout=None, _host=None):\n        \"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\n    \n        To make an async_req request, set the async_req parameter.\n    \n        :param resource_path: Path to method endpoint.\n        :param method: Method to call.\n        :param path_params: Path parameters in the url.\n        :param query_params: Query parameters in the url.\n        :param header_params: Header parameters to be\n            placed in the request header.\n        :param body: Request body.\n        :param post_params dict: Request post form parameters,\n            for `application/x-www-form-urlencoded`, `multipart/form-data`.\n        :param auth_settings list: Auth Settings names for the request.\n        :param response: Response data type.\n        :param files dict: key -> filename, value -> filepath,\n            for `multipart/form-data`.\n        :param async_req bool: execute request asynchronously\n        :param _return_http_data_only: response data without head status code\n                                       and headers\n        :param collection_formats: dict of collection formats for path, query,\n            header, and post parameters.\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        :return:\n            If async_req parameter is True,\n            the request will be called asynchronously.\n            The method will return the request thread.\n            If parameter async_req is False or missing,\n            then the method will return the response directly.\n        \"\"\"\n        if not async_req:\n>           return self.__call_api(resource_path, method,\n                                   path_params, query_params, header_params,\n                                   body, post_params, files,\n                                   response_type, auth_settings,\n                                   _return_http_data_only, collection_formats,\n                                   _preload_content, _request_timeout, _host)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:348: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202133dd0>\nresource_path = '/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-d73d44f4/llminferenceserviceconfigs'\nmethod = 'POST'\npath_params = [('group', 'serving.kserve.io'), ('version', 'v1alpha1'), ('namespace', 'e2e-test-llm-inference-service-d73d44f4'), ('plural', 'llminferenceserviceconfigs')]\nquery_params = []\nheader_params = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\npost_params = [], files = {}, response_type = 'object'\nauth_settings = ['BearerToken'], _return_http_data_only = True\ncollection_formats = {}, _preload_content = True, _request_timeout = None\n_host = None\n\n    def __call_api(\n            self, resource_path, method, path_params=None,\n            query_params=None, header_params=None, body=None, post_params=None,\n            files=None, response_type=None, auth_settings=None,\n            _return_http_data_only=None, collection_formats=None,\n            _preload_content=True, _request_timeout=None, _host=None):\n    \n        config = self.configuration\n    \n        # header parameters\n        header_params = header_params or {}\n        header_params.update(self.default_headers)\n        if self.cookie:\n            header_params['Cookie'] = self.cookie\n        if header_params:\n            header_params = self.sanitize_for_serialization(header_params)\n            header_params = dict(self.parameters_to_tuples(header_params,\n                                                           collection_formats))\n    \n        # path parameters\n        if path_params:\n            path_params = self.sanitize_for_serialization(path_params)\n            path_params = self.parameters_to_tuples(path_params,\n                                                    collection_formats)\n            for k, v in path_params:\n                # specified safe chars, encode everything\n                resource_path = resource_path.replace(\n                    '{%s}' % k,\n                    quote(str(v), safe=config.safe_chars_for_path_param)\n                )\n    \n        # query parameters\n        if query_params:\n            query_params = self.sanitize_for_serialization(query_params)\n            query_params = self.parameters_to_tuples(query_params,\n                                                     collection_formats)\n    \n        # post parameters\n        if post_params or files:\n            post_params = post_params if post_params else []\n            post_params = self.sanitize_for_serialization(post_params)\n            post_params = self.parameters_to_tuples(post_params,\n                                                    collection_formats)\n            post_params.extend(self.files_parameters(files))\n    \n        # auth setting\n        self.update_params_for_auth(header_params, query_params, auth_settings)\n    \n        # body\n        if body:\n            body = self.sanitize_for_serialization(body)\n    \n        # request url\n        if _host is None:\n            url = self.configuration.host + resource_path\n        else:\n            # use server/host defined in path or operation instead\n            url = _host + resource_path\n    \n        # perform request and return response\n>       response_data = self.request(\n            method, url, query_params=query_params, headers=header_params,\n            post_params=post_params, body=body,\n            _preload_content=_preload_content,\n            _request_timeout=_request_timeout)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:180: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.api_client.ApiClient object at 0x7fc202133dd0>\nmethod = 'POST'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-d73d44f4/llminferenceserviceconfigs'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\npost_params = []\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\n_preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                post_params=None, body=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Makes the HTTP request using RESTClient.\"\"\"\n        if method == \"GET\":\n            return self.rest_client.GET(url,\n                                        query_params=query_params,\n                                        _preload_content=_preload_content,\n                                        _request_timeout=_request_timeout,\n                                        headers=headers)\n        elif method == \"HEAD\":\n            return self.rest_client.HEAD(url,\n                                         query_params=query_params,\n                                         _preload_content=_preload_content,\n                                         _request_timeout=_request_timeout,\n                                         headers=headers)\n        elif method == \"OPTIONS\":\n            return self.rest_client.OPTIONS(url,\n                                            query_params=query_params,\n                                            headers=headers,\n                                            _preload_content=_preload_content,\n                                            _request_timeout=_request_timeout)\n        elif method == \"POST\":\n>           return self.rest_client.POST(url,\n                                         query_params=query_params,\n                                         headers=headers,\n                                         post_params=post_params,\n                                         _preload_content=_preload_content,\n                                         _request_timeout=_request_timeout,\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/api_client.py:391: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc202133e50>\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-d73d44f4/llminferenceserviceconfigs'\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nquery_params = [], post_params = []\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\n_preload_content = True, _request_timeout = None\n\n    def POST(self, url, headers=None, query_params=None, post_params=None,\n             body=None, _preload_content=True, _request_timeout=None):\n>       return self.request(\"POST\", url,\n                            headers=headers,\n                            query_params=query_params,\n                            post_params=post_params,\n                            _preload_content=_preload_content,\n                            _request_timeout=_request_timeout,\n                            body=body)\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:279: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <kubernetes.client.rest.RESTClientObject object at 0x7fc202133e50>\nmethod = 'POST'\nurl = 'https://abd8b686d1ff342e4952c8ff19c59c6b-970430a80edceb74.elb.us-east-1.amazonaws.com:6443/apis/serving.kserve.io/v1alpha1/namespaces/e2e-test-llm-inference-service-d73d44f4/llminferenceserviceconfigs'\nquery_params = []\nheaders = {'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'OpenAPI-Generator/32.0.1/python'}\nbody = {'apiVersion': 'serving.kserve.io/v1alpha1', 'kind': 'LLMInferenceServiceConfig', 'metadata': {'name': 'router-custom-...t-llm-inference-service-d73d44f4'}, 'spec': {'router': {'gateway': {}, 'route': {'http': {'spec': {'rules': [...]}}}}}}\npost_params = {}, _preload_content = True, _request_timeout = None\n\n    def request(self, method, url, query_params=None, headers=None,\n                body=None, post_params=None, _preload_content=True,\n                _request_timeout=None):\n        \"\"\"Perform requests.\n    \n        :param method: http request method\n        :param url: http request url\n        :param query_params: query parameters in the url\n        :param headers: http request headers\n        :param body: request json body, for `application/json`\n        :param post_params: request post parameters,\n                            `application/x-www-form-urlencoded`\n                            and `multipart/form-data`\n        :param _preload_content: if False, the urllib3.HTTPResponse object will\n                                 be returned without reading/decoding response\n                                 data. Default is True.\n        :param _request_timeout: timeout setting for this request. If one\n                                 number provided, it will be total request\n                                 timeout. It can also be a pair (tuple) of\n                                 (connection, read) timeouts.\n        \"\"\"\n        method = method.upper()\n        assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',\n                          'PATCH', 'OPTIONS']\n    \n        if post_params and body:\n            raise ApiValueError(\n                \"body parameter cannot be used with post_params parameter.\"\n            )\n    \n        post_params = post_params or {}\n        headers = headers or {}\n    \n        timeout = None\n        if _request_timeout:\n            if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)):  # noqa: E501,F821\n                timeout = urllib3.Timeout(total=_request_timeout)\n            elif (isinstance(_request_timeout, tuple) and\n                  len(_request_timeout) == 2):\n                timeout = urllib3.Timeout(\n                    connect=_request_timeout[0], read=_request_timeout[1])\n    \n        if 'Content-Type' not in headers:\n            headers['Content-Type'] = 'application/json'\n    \n        try:\n            # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`\n            if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:\n                if query_params:\n                    url += '?' + urlencode(query_params)\n                if (re.search('json', headers['Content-Type'], re.IGNORECASE) or\n                        headers['Content-Type'] == 'application/apply-patch+yaml'):\n                    if headers['Content-Type'] == 'application/json-patch+json':\n                        if not isinstance(body, list):\n                            headers['Content-Type'] = \\\n                                'application/strategic-merge-patch+json'\n                    request_body = None\n                    if body is not None:\n                        request_body = json.dumps(body)\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'application/x-www-form-urlencoded':  # noqa: E501\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=False,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                elif headers['Content-Type'] == 'multipart/form-data':\n                    # must del headers['Content-Type'], or the correct\n                    # Content-Type which generated by urllib3 will be\n                    # overwritten.\n                    del headers['Content-Type']\n                    r = self.pool_manager.request(\n                        method, url,\n                        fields=post_params,\n                        encode_multipart=True,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                # Pass a `string` parameter directly in the body to support\n                # other content types than Json when `body` argument is\n                # provided in serialized form\n                elif isinstance(body, str) or isinstance(body, bytes):\n                    request_body = body\n                    r = self.pool_manager.request(\n                        method, url,\n                        body=request_body,\n                        preload_content=_preload_content,\n                        timeout=timeout,\n                        headers=headers)\n                else:\n                    # Cannot generate the request from given parameters\n                    msg = \"\"\"Cannot prepare a request message for provided\n                             arguments. Please check that your arguments match\n                             declared content type.\"\"\"\n                    raise ApiException(status=0, reason=msg)\n            # For `GET`, `HEAD`\n            else:\n                r = self.pool_manager.request(method, url,\n                                              fields=query_params,\n                                              preload_content=_preload_content,\n                                              timeout=timeout,\n                                              headers=headers)\n        except urllib3.exceptions.SSLError as e:\n            msg = \"{0}\\n{1}\".format(type(e).__name__, str(e))\n            raise ApiException(status=0, reason=msg)\n    \n        if _preload_content:\n            r = RESTResponse(r)\n    \n            # In the python 3, the response.data is bytes.\n            # we need to decode it to string.\n            if six.PY3:\n                r.data = r.data.decode('utf8')\n    \n            # log response body\n            logger.debug(\"response body: %s\", r.data)\n    \n        if not 200 <= r.status <= 299:\n>           raise ApiException(http_resp=r)\nE           kubernetes.client.exceptions.ApiException: (500)\nE           Reason: Internal Server Error\nE           HTTP response headers: HTTPHeaderDict({'Audit-Id': 'ec254936-5f14-42fa-86e9-bae4267dd9cf', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', 'X-Kubernetes-Pf-Flowschema-Uid': 'ff0b8d77-f0bc-468d-a86a-0524cad8e456', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'a7ead034-f650-4220-8a0e-0379eadce096', 'Date': 'Tue, 28 Jul 2026 17:24:07 GMT', 'Content-Length': '701'})\nE           HTTP response body: {\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"Internal error occurred: failed calling webhook \\\"llminferenceserviceconfig.kserve-webhook-server.v1alpha1.validator\\\": failed to call webhook: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/validate-serving-kserve-io-v1alpha1-llminferenceserviceconfig?timeout=10s\\\": EOF\",\"reason\":\"InternalError\",\"details\":{\"causes\":[{\"message\":\"failed calling webhook \\\"llminferenceserviceconfig.kserve-webhook-server.v1alpha1.validator\\\": failed to call webhook: Post \\\"https://llmisvc-webhook-server-service.kserve.svc:443/validate-serving-kserve-io-v1alpha1-llminferenceserviceconfig?timeout=10s\\\": EOF\"}]},\"code\":500}\n\n../../python/kserve/.venv/lib64/python3.11/site-packages/kubernetes/client/rest.py:238: ApiException"}, "teardown": {"duration": 0.00047286500193877146, "outcome": "passed", "longrepr": "[gw1] 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_flow_control_smoke[flow-control-utilization-detector]> 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_flow_control.py", "lineno": 47}, {"message": "The test <Function test_flow_control_smoke[flow-control-concurrency-detector]> 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_flow_control.py", "lineno": 47}, {"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-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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"message": "The test <Function test_llm_inference_service[router-managed-scheduler-with-tokenizer-kvcache-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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}, {"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_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": 92}, {"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": 243}, {"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": 243}, {"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": 243}, {"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": 243}]}