gpustack-runtime 0.2.5.post3__tar.gz → 0.2.5.post4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. gpustack_runtime-0.2.5.post4/ADOPTERS.md +12 -0
  2. gpustack_runtime-0.2.5.post4/AGENTS.md +85 -0
  3. gpustack_runtime-0.2.5.post4/DCO +34 -0
  4. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/LICENSE +1 -1
  5. gpustack_runtime-0.2.5.post4/PKG-INFO +82 -0
  6. gpustack_runtime-0.2.5.post4/README.md +55 -0
  7. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/_version.py +2 -2
  8. gpustack_runtime-0.2.5.post4/gpustack_runtime/_version_appendix.py +1 -0
  9. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/__init__.py +3 -1
  10. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/k8s/devicemanager/__init__.py +56 -6
  11. gpustack_runtime-0.2.5.post3/gpustack_runtime/deployer/kuberentes.py → gpustack_runtime-0.2.5.post4/gpustack_runtime/deployer/kubernetes.py +81 -13
  12. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/mkdocs.yml +1 -1
  13. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/specs/2026-08-14-detector-alignment-and-workload-exit-status.md +4 -4
  14. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_kubernetes_status.py +1 -1
  15. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_logs_options.py +2 -2
  16. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_privileged.py +1 -1
  17. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_resource_injection_policy.py +1 -1
  18. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_runtime_class.py +1 -1
  19. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_termination_grace_period.py +3 -3
  20. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_visible_devices_ordering.py +3 -3
  21. gpustack_runtime-0.2.5.post4/tests/gpustack_runtime/deployer/test_workload_resource_injection_policy.py +347 -0
  22. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_workload_status.py +2 -2
  23. gpustack_runtime-0.2.5.post3/PKG-INFO +0 -64
  24. gpustack_runtime-0.2.5.post3/README.md +0 -37
  25. gpustack_runtime-0.2.5.post3/gpustack_runtime/_version_appendix.py +0 -1
  26. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/.codespelldict +0 -0
  27. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/.codespellrc +0 -0
  28. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/.dockerignore +0 -0
  29. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/.gitattributes +0 -0
  30. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/.gitignore +0 -0
  31. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/.pre-commit-config.yaml +0 -0
  32. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/.python-version +0 -0
  33. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/Makefile +0 -0
  34. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/deploy/manifests/docker-compose.yaml +0 -0
  35. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/deploy/manifests/kubernetes.yaml +0 -0
  36. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/docs/index.md +0 -0
  37. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/docs/modules/gpustack_runtime.deployer.md +0 -0
  38. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/docs/modules/gpustack_runtime.detector.md +0 -0
  39. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/docs/modules/gpustack_runtime.md +0 -0
  40. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/__init__.py +0 -0
  41. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/__main__.py +0 -0
  42. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/_version.pyi +0 -0
  43. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/cmds/__init__.py +0 -0
  44. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/cmds/__types__.py +0 -0
  45. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/cmds/deployer.py +0 -0
  46. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/cmds/detector.py +0 -0
  47. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/cmds/images.py +0 -0
  48. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/__patches__.py +0 -0
  49. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/__types__.py +0 -0
  50. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/__utils__.py +0 -0
  51. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/__init__.py +0 -0
  52. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/__types__.py +0 -0
  53. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/__utils__.py +0 -0
  54. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/amd.py +0 -0
  55. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/ascend.py +0 -0
  56. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/hygon.py +0 -0
  57. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/iluvatar.py +0 -0
  58. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/metax.py +0 -0
  59. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/cdi/thead.py +0 -0
  60. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/docker.py +0 -0
  61. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/deployer/podman.py +0 -0
  62. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/__init__.py +0 -0
  63. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/__types__.py +0 -0
  64. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/__utils__.py +0 -0
  65. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/amd.py +0 -0
  66. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/ascend.py +0 -0
  67. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/cambricon.py +0 -0
  68. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/hygon.py +0 -0
  69. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/iluvatar.py +0 -0
  70. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/metax.py +0 -0
  71. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/mthreads.py +0 -0
  72. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/nvidia.py +0 -0
  73. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pyamdgpu/__init__.py +0 -0
  74. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pyamdsmi/__init__.py +0 -0
  75. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pycndev/__init__.py +0 -0
  76. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pydcmi/__init__.py +0 -0
  77. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pydmi/__init__.py +0 -0
  78. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pyhgml/__init__.py +0 -0
  79. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pyhgml/libhgml.so +0 -0
  80. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pyhgml/libuki.so +0 -0
  81. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pyhsa/__init__.py +0 -0
  82. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pyixml/__init__.py +0 -0
  83. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pymtml/__init__.py +0 -0
  84. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pymxsml/__init__.py +0 -0
  85. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pynvml/__init__.py +0 -0
  86. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/pyrocmsmi/__init__.py +0 -0
  87. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/detector/thead.py +0 -0
  88. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/envs.py +0 -0
  89. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/gpustack_runtime/logging.py +0 -0
  90. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/hatch.toml +0 -0
  91. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/pack/Dockerfile +0 -0
  92. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/pack/Dockerfile.dummy +0 -0
  93. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/pyproject.toml +0 -0
  94. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/pytest.ini +0 -0
  95. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/ruff.toml +0 -0
  96. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/__init__.py +0 -0
  97. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/test_compare_versions.json +0 -0
  98. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/test_correct_runner_image.json +0 -0
  99. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json.json +0 -0
  100. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json_multiple_jsons.json +0 -0
  101. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json_multiple_yamls.yaml +0 -0
  102. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json_single_json.json +0 -0
  103. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json_single_yaml.yaml +0 -0
  104. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/fixtures/test_nginx_entrypoint.sh +0 -0
  105. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_ascend_ranktable.py +0 -0
  106. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_docker_status.py +0 -0
  107. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_podman_status.py +0 -0
  108. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/deployer/test_utils.py +0 -0
  109. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/fixtures/__init__.py +0 -0
  110. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/README.md +0 -0
  111. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_amd_mi300x.json +0 -0
  112. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_amd_mi308x.json +0 -0
  113. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_amd_rx7800xt.json +0 -0
  114. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_ascend_310p3.json +0 -0
  115. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_ascend_910b2.json +0 -0
  116. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_hygon_k100ai.json +0 -0
  117. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_metax_c500.json +0 -0
  118. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_gb10.json +0 -0
  119. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_h100.json +0 -0
  120. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_h100_mig.json +0 -0
  121. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_h200.json +0 -0
  122. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_rtx4080super.json +0 -0
  123. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_rtx4090_48g.json +0 -0
  124. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_rtx4090d.json +0 -0
  125. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_rtx5090d.json +0 -0
  126. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/detect_output_thead_ppu.json +0 -0
  127. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_amd_mi300x.json +0 -0
  128. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_amd_mi308x.json +0 -0
  129. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_amd_rx7800xt.json +0 -0
  130. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_ascend_310p3.json +0 -0
  131. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_ascend_910b2.json +0 -0
  132. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_hygon_k100ai.json +0 -0
  133. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_metax_c500.json +0 -0
  134. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_mthreads_s5000.json +0 -0
  135. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_h100.json +0 -0
  136. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_h100_mig.json +0 -0
  137. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_h200.json +0 -0
  138. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_rtx4080super.json +0 -0
  139. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_rtx4090_48g.json +0 -0
  140. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_rtx4090d.json +0 -0
  141. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_rtx5090d.json +0 -0
  142. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/samples/topology_output_thead_ppu.json +0 -0
  143. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_amd.py +0 -0
  144. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_ascend.py +0 -0
  145. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_cambricon.py +0 -0
  146. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_detector_cli.py +0 -0
  147. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_detector_types.py +0 -0
  148. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_detector_utils.py +0 -0
  149. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_hygon.py +0 -0
  150. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_iluvatar.py +0 -0
  151. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_metax.py +0 -0
  152. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_mig_devices.py +0 -0
  153. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_mthreads.py +0 -0
  154. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_nvidia.py +0 -0
  155. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_pycndev.py +0 -0
  156. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_pydmi.py +0 -0
  157. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_samples.py +0 -0
  158. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/tests/gpustack_runtime/detector/test_thead.py +0 -0
  159. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/uv.lock +0 -0
  160. {gpustack_runtime-0.2.5.post3 → gpustack_runtime-0.2.5.post4}/uv.toml +0 -0
@@ -0,0 +1,12 @@
1
+ # Who's using GPUStack Runtime
2
+
3
+ GPUStack Runtime is used by a growing range of companies and projects to detect accelerator (GPU/NPU) resources and run accelerator workloads on Docker, Kubernetes and Podman.
4
+
5
+ If you are using GPUStack Runtime and your name is not on this list, please send us a PR!
6
+
7
+ ## Companies/Projects using GPUStack Runtime in production
8
+
9
+ These companies and projects are using GPUStack Runtime in production. If your company is using GPUStack Runtime, open a PR to add your company or project name and a description of how you are using GPUStack Runtime.
10
+
11
+ | Company / Project | Use Case |
12
+ | --- | --- |
@@ -0,0 +1,85 @@
1
+ # GPUStack Runtime
2
+
3
+ A Python library with a unified interface for detecting accelerator (GPU/NPU) resources and
4
+ launching and managing GPU workloads on Docker, Kubernetes and Podman.
5
+
6
+ ## Project Structure
7
+
8
+ - `gpustack_runtime/` — the library.
9
+ - `detector/` — one detector per vendor (`nvidia.py`, `amd.py`, `ascend.py`, `cambricon.py`,
10
+ `hygon.py`, `iluvatar.py`, `metax.py`, `mthreads.py`, `thead.py`), plus the `py*` packages,
11
+ ctypes bindings to vendor management libraries (`pynvml`, `pydcmi`, `pycndev`, ...).
12
+ - `deployer/` — one deployer per container runtime (`docker.py`, `kubernetes.py`, `podman.py`),
13
+ `cdi/` for vendor CDI spec handling, `k8s/` for Kubernetes helpers, and `__patches__.py` for
14
+ the vendored Podman client patch.
15
+ - `cmds/` — CLI subcommands behind the `gpustack-runtime` entrypoint (`__main__.py`).
16
+ - `envs.py` — environment variables; `logging.py` — logging helpers.
17
+ - `tests/gpustack_runtime/` — pytest suite mirroring the package; `detector/samples/` holds
18
+ captured vendor-tool outputs used as fixtures.
19
+ - `docs/` — MkDocs site; `docs/modules/` is API reference rendered from docstrings by
20
+ mkdocstrings.
21
+ - `specs/` — design records.
22
+ - `pack/` / `deploy/` — container image build and deployment manifests.
23
+
24
+ ## Architecture
25
+
26
+ Detection: each vendor detector in `gpustack_runtime/detector/` probes its vendor library through
27
+ the matching `py*` binding and reports `Device`s with topology. `detector/__init__.py` owns the
28
+ registry (`_DETECTORS`) and the aggregate entry points (`supported_list()`, `detect_devices()`).
29
+
30
+ Deployment: `deployer/__init__.py` owns the registry (`_DEPLOYERS`) and picks the first available
31
+ runtime (Docker, Kubernetes, Podman). A `WorkloadPlan` describes the desired containers; the
32
+ deployer injects vendor resources (CDI devices, environment variables, mounts) and returns a
33
+ workload handle for inspect/logs/exec/delete. Shared types live in `deployer/__types__.py`,
34
+ including the `OperationError` / `UnsupportedError` error contract.
35
+
36
+ ## Finding sources
37
+
38
+ - Confirm the checkout, branch and uncommitted changes before reasoning about behavior. The
39
+ published wheel or a merged PR may describe a different revision.
40
+ - Docstrings are the usage contract: `make docs` renders them into `site/`. Specs under
41
+ `specs/` own design rationale; current code establishes what this checkout implements. Report
42
+ disagreement rather than silently choosing one.
43
+ - For a vendor behavior claim, read the matching `py*` binding and the detector tests under
44
+ `tests/gpustack_runtime/detector/`; captured outputs live in `detector/samples/`.
45
+ - For a concrete error, search its stable text locally first. When it concerns an upstream
46
+ dependency (docker, kubernetes, podman clients), check that project's issues and pinned version
47
+ in `pyproject.toml` / `uv.lock`.
48
+
49
+ ## Development
50
+
51
+ Setup is `make install` (uv sync plus pre-commit hooks). Day-to-day targets:
52
+
53
+ - `make lint` — pre-commit on all files: ruff check/format, codespell, commitizen.
54
+ - `make test` — pytest.
55
+ - `make docs` — build the MkDocs site into `site/` (git-ignored).
56
+ - `make build` — build wheel and sdist into `dist/` (git-ignored).
57
+ - `make package` — build the container image with docker buildx; `PACKAGE_PUSH=true` pushes.
58
+
59
+ `gpustack_runtime/_version.py` is generated by hatch-vcs and `_version_appendix.py` by
60
+ `make prepare`; never hand-edit either.
61
+
62
+ ### Python conventions
63
+
64
+ - Prefer clarity over cleverness to simplify long-term maintenance.
65
+ - Start every package module with `from __future__ import annotations as __future_annotations__`.
66
+ - Follow the ruff configuration in `ruff.toml`; run `make lint` whenever modifying Python source.
67
+ - Type-annotate public APIs and re-export them from the package `__init__.py` (`__all__`).
68
+ - Write Google-style docstrings; they render into the published API reference.
69
+ - Handle errors explicitly. Deployers raise `OperationError` or `UnsupportedError` from
70
+ `deployer.__types__` instead of leaking runtime-client exceptions. Detectors degrade to an
71
+ empty result and log at debug level rather than failing on a host without that vendor.
72
+ - Keep private helpers in double-underscore modules (`__types__.py`, `__utils__.py`); import them
73
+ through the package, not across subpackages.
74
+ - Keep concurrency simple, safe and justified; minimize mutable shared state.
75
+ - Keep comments plain and short: no emoji, no decorative symbols. State the point in words.
76
+
77
+ ### Testing conventions
78
+
79
+ - pytest; tests mirror the package layout under `tests/gpustack_runtime/`.
80
+ - Never require real hardware or a real container runtime. Detector tests fake the `py*` vendor
81
+ binding in the test module; deployer tests fake the runtime client.
82
+ - Reuse captured vendor outputs from `tests/gpustack_runtime/detector/samples/` and shared
83
+ fixtures from `fixtures/` instead of inventing new sample data.
84
+ - Verify one behavior or contract per test; assert observable state, not implementation details.
85
+ - Keep tests deterministic and repeatable: no wall-clock, ordering or randomness dependence.
@@ -0,0 +1,34 @@
1
+ Developer Certificate of Origin
2
+ Version 1.1
3
+
4
+ Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
5
+
6
+ Everyone is permitted to copy and distribute verbatim copies of this
7
+ license document, but changing it is not allowed.
8
+
9
+
10
+ Developer's Certificate of Origin 1.1
11
+
12
+ By making a contribution to this project, I certify that:
13
+
14
+ (a) The contribution was created in whole or in part by me and I
15
+ have the right to submit it under the open source license
16
+ indicated in the file; or
17
+
18
+ (b) The contribution is based upon previous work that, to the best
19
+ of my knowledge, is covered under an appropriate open source
20
+ license and I have the right under that license to submit that
21
+ work with modifications, whether created in whole or in part
22
+ by me, under the same open source license (unless I am
23
+ permitted to submit under a different license), as indicated
24
+ in the file; or
25
+
26
+ (c) The contribution was provided directly to me by some other
27
+ person who certified (a), (b) or (c) and I have not modified
28
+ it.
29
+
30
+ (d) I understand and agree that this project and the contribution
31
+ are public and that a record of the contribution (including all
32
+ personal information I submit with it, including my sign-off) is
33
+ maintained indefinitely and may be redistributed consistent with
34
+ this project or the open source license(s) involved.
@@ -175,7 +175,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
175
175
 
176
176
  END OF TERMS AND CONDITIONS
177
177
 
178
- Copyright (c) 2025 The GPUStack Authors
178
+ Copyright (c) 2026 The GPUStack Authors
179
179
 
180
180
  Licensed under the Apache License, Version 2.0 (the "License");
181
181
  you may not use this file except in compliance with the License.
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.5
2
+ Name: gpustack-runtime
3
+ Version: 0.2.5.post4
4
+ Summary: GPUStack Runtime is library for detecting GPU resources and launching GPU workloads.
5
+ Project-URL: Homepage, https://github.com/gpustack/runtime
6
+ Project-URL: Bug Tracker, https://github.com/gpustack/gpustack/issues
7
+ Author-email: GPUStack Authors <contact@gpustack.ai>
8
+ License-Expression: Apache-2.0
9
+ License-File: LICENSE
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Python: >=3.10
16
+ Requires-Dist: argcomplete>=3.6.3
17
+ Requires-Dist: cachetools>=5.5.2
18
+ Requires-Dist: docker>=7.1.0
19
+ Requires-Dist: gpustack-runner>=0.1.29
20
+ Requires-Dist: kubernetes>=33.1.0
21
+ Requires-Dist: mthreads-ml-py>=2.2.10
22
+ Requires-Dist: nvidia-ml-py>=13.580.65
23
+ Requires-Dist: podman==5.6.0
24
+ Requires-Dist: pyyaml
25
+ Requires-Dist: tqdm
26
+ Description-Content-Type: text/markdown
27
+
28
+ # GPUStack Runtime
29
+
30
+ [![License](https://img.shields.io/github/license/gpustack/runtime?logo=apache&label=License)](./LICENSE)
31
+ [![PyPI](https://img.shields.io/pypi/v/gpustack-runtime?logo=pypi&label=PyPI)](https://pypi.org/project/gpustack-runtime/)
32
+ [![Latest Release](https://img.shields.io/github/v/release/gpustack/runtime?logo=semanticrelease&label=Release&include_prereleases)](https://github.com/gpustack/runtime/releases/latest)
33
+ [![Docker Pulls](https://img.shields.io/docker/pulls/gpustack/runtime?logo=docker&logoColor=fff&label=Docker%20Pulls)](https://hub.docker.com/r/gpustack/runtime)
34
+ [![Ask DeepWiki](https://img.shields.io/badge/Ask_DeepWiki-purple?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAPoAAAD6AG1e1JrAAACIUlEQVRYw+2XP2gUQRTGv7d3JhYWQawkIBaCVWzETos0gmAnVoKNTSoLK0E7EQQrC20sBVFBtLPQRgTBtBaKjYgIQUSxiJq7fT+LvCGPJZdNLt4dQj5Y3u7sznzfzLw/s9IO/icANiniCujEfWdsQgBLxAbsbraPZcmBfcAt4DNwKQsZNfEUsAB8YRV12LfA6ZHuedg7AO7ed/c+UBcbQhbiu+6wXIM6EnZWkszMJe2Ke0n6I2la0v51hFeSMLN6OwIK6jJwEBdUYb2MAxRSz6sY4geiahFgLe1Hwq6YWe3us8AN4FQQU4QM64SPY69Xyr43fADgNjAPXHb3peSsD4FDQ0VLEjAHvIhBPS6AHvA1bBO9JPAXcHFbIRtJ5yzwIQZ9CZwAusDJENIkLqsG8DpNyIZJwSUk9wLHgakcesC1JCCjiHm1kYDNOEjptCxpSVK/8f73OFLxPLAYM3oCzEX7MXf/lJbc/8kWpA4HgQdpYI9IWAbeh83whi84cHXL+58EPBoQhnmm94EzwE3gZ2p/Dhzdbhg+TaRr01x7ftb4/jBwFzjXrCvDpmLW9crVLNeR9CaapoGemb2TdCERW1tNaBNQ8jktwmozqwtpqRNtdWAjARYk39IS12ZWRX7vmJmA71nQZgi36gN7gCvAj5xc3P0jcH7kx7Ik5IC73wsh14GZsZySow5002l4Jr0b6+m4eSyvpAn8lEzsx2QHo8RfUrlN+uPq4ksAAAAASUVORK5CYII=)](https://deepwiki.com/gpustack/runtime)
35
+
36
+ GPUStack Runtime offers a unified interface for detecting GPU resources and managing GPU workloads.
37
+
38
+ ## Features
39
+
40
+ - Detect a wide range of GPU and accelerator resources:
41
+
42
+ - AMD GPU
43
+ - Ascend NPU
44
+ - Cambricon MLU
45
+ - Hygon DCU
46
+ - Iluvatar GPU
47
+ - MetaX GPU
48
+ - Moore Threads GPU
49
+ - NVIDIA GPU
50
+ - T-Head PPU
51
+
52
+ - Manage GPU workloads on the following platforms:
53
+
54
+ - Docker
55
+ - Kubernetes
56
+ - Podman (>=4.9, experimental support via the `CONTAINER_HOST=http+unix:///path/to/podman/socket` environment variable)
57
+
58
+ Contributions to support additional GPU resources are welcome!
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ pip install gpustack-runtime
64
+ ```
65
+
66
+ ## Documentation
67
+
68
+ The API reference renders from docstrings. Build the site locally with `make docs` and open
69
+ `site/index.html`.
70
+
71
+ ## Contributing
72
+
73
+ Contributions are welcome. Commits must carry a `Signed-off-by` line certifying the
74
+ [Developer Certificate of Origin](./DCO).
75
+
76
+ Using GPUStack Runtime in production? Add your company or project to [ADOPTERS.md](./ADOPTERS.md)
77
+ via pull request.
78
+
79
+ ## License
80
+
81
+ Copyright (c) 2026 The GPUStack Authors. Licensed under the
82
+ [Apache License 2.0](./LICENSE).
@@ -0,0 +1,55 @@
1
+ # GPUStack Runtime
2
+
3
+ [![License](https://img.shields.io/github/license/gpustack/runtime?logo=apache&label=License)](./LICENSE)
4
+ [![PyPI](https://img.shields.io/pypi/v/gpustack-runtime?logo=pypi&label=PyPI)](https://pypi.org/project/gpustack-runtime/)
5
+ [![Latest Release](https://img.shields.io/github/v/release/gpustack/runtime?logo=semanticrelease&label=Release&include_prereleases)](https://github.com/gpustack/runtime/releases/latest)
6
+ [![Docker Pulls](https://img.shields.io/docker/pulls/gpustack/runtime?logo=docker&logoColor=fff&label=Docker%20Pulls)](https://hub.docker.com/r/gpustack/runtime)
7
+ [![Ask DeepWiki](https://img.shields.io/badge/Ask_DeepWiki-purple?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAPoAAAD6AG1e1JrAAACIUlEQVRYw+2XP2gUQRTGv7d3JhYWQawkIBaCVWzETos0gmAnVoKNTSoLK0E7EQQrC20sBVFBtLPQRgTBtBaKjYgIQUSxiJq7fT+LvCGPJZdNLt4dQj5Y3u7sznzfzLw/s9IO/icANiniCujEfWdsQgBLxAbsbraPZcmBfcAt4DNwKQsZNfEUsAB8YRV12LfA6ZHuedg7AO7ed/c+UBcbQhbiu+6wXIM6EnZWkszMJe2Ke0n6I2la0v51hFeSMLN6OwIK6jJwEBdUYb2MAxRSz6sY4geiahFgLe1Hwq6YWe3us8AN4FQQU4QM64SPY69Xyr43fADgNjAPXHb3peSsD4FDQ0VLEjAHvIhBPS6AHvA1bBO9JPAXcHFbIRtJ5yzwIQZ9CZwAusDJENIkLqsG8DpNyIZJwSUk9wLHgakcesC1JCCjiHm1kYDNOEjptCxpSVK/8f73OFLxPLAYM3oCzEX7MXf/lJbc/8kWpA4HgQdpYI9IWAbeh83whi84cHXL+58EPBoQhnmm94EzwE3gZ2p/Dhzdbhg+TaRr01x7ftb4/jBwFzjXrCvDpmLW9crVLNeR9CaapoGemb2TdCERW1tNaBNQ8jktwmozqwtpqRNtdWAjARYk39IS12ZWRX7vmJmA71nQZgi36gN7gCvAj5xc3P0jcH7kx7Ik5IC73wsh14GZsZySow5002l4Jr0b6+m4eSyvpAn8lEzsx2QHo8RfUrlN+uPq4ksAAAAASUVORK5CYII=)](https://deepwiki.com/gpustack/runtime)
8
+
9
+ GPUStack Runtime offers a unified interface for detecting GPU resources and managing GPU workloads.
10
+
11
+ ## Features
12
+
13
+ - Detect a wide range of GPU and accelerator resources:
14
+
15
+ - AMD GPU
16
+ - Ascend NPU
17
+ - Cambricon MLU
18
+ - Hygon DCU
19
+ - Iluvatar GPU
20
+ - MetaX GPU
21
+ - Moore Threads GPU
22
+ - NVIDIA GPU
23
+ - T-Head PPU
24
+
25
+ - Manage GPU workloads on the following platforms:
26
+
27
+ - Docker
28
+ - Kubernetes
29
+ - Podman (>=4.9, experimental support via the `CONTAINER_HOST=http+unix:///path/to/podman/socket` environment variable)
30
+
31
+ Contributions to support additional GPU resources are welcome!
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install gpustack-runtime
37
+ ```
38
+
39
+ ## Documentation
40
+
41
+ The API reference renders from docstrings. Build the site locally with `make docs` and open
42
+ `site/index.html`.
43
+
44
+ ## Contributing
45
+
46
+ Contributions are welcome. Commits must carry a `Signed-off-by` line certifying the
47
+ [Developer Certificate of Origin](./DCO).
48
+
49
+ Using GPUStack Runtime in production? Add your company or project to [ADOPTERS.md](./ADOPTERS.md)
50
+ via pull request.
51
+
52
+ ## License
53
+
54
+ Copyright (c) 2026 The GPUStack Authors. Licensed under the
55
+ [Apache License 2.0](./LICENSE).
@@ -27,8 +27,8 @@ version_tuple: VERSION_TUPLE
27
27
  __commit_id__: COMMIT_ID
28
28
  commit_id: COMMIT_ID
29
29
 
30
- __version__ = version = '0.2.5.post3'
31
- __version_tuple__ = version_tuple = (0, 2, 5, 'post3')
30
+ __version__ = version = '0.2.5.post4'
31
+ __version_tuple__ = version_tuple = (0, 2, 5, 'post4')
32
32
  try:
33
33
  from ._version_appendix import git_commit
34
34
  __commit_id__ = commit_id = git_commit
@@ -0,0 +1 @@
1
+ git_commit = "089358e"
@@ -36,7 +36,8 @@ from .docker import (
36
36
  DockerWorkloadPlan,
37
37
  DockerWorkloadStatus,
38
38
  )
39
- from .kuberentes import (
39
+ from .k8s.devicemanager import KubernetesResourceInjectionPolicyEnum
40
+ from .kubernetes import (
40
41
  KubernetesDeployer,
41
42
  KubernetesWorkloadPlan,
42
43
  KubernetesWorkloadStatus,
@@ -595,6 +596,7 @@ __all__ = [
595
596
  "ContainerSecurity",
596
597
  "DockerWorkloadPlan",
597
598
  "DockerWorkloadStatus",
599
+ "KubernetesResourceInjectionPolicyEnum",
598
600
  "KubernetesWorkloadPlan",
599
601
  "KubernetesWorkloadStatus",
600
602
  "OperationError",
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations as __future_annotations__
2
2
 
3
3
  import stat
4
+ from enum import Enum
4
5
  from functools import lru_cache
5
6
  from pathlib import Path
6
7
  from typing import TYPE_CHECKING, Any, Literal
@@ -11,6 +12,36 @@ if TYPE_CHECKING:
11
12
  from collections.abc import Callable, Mapping
12
13
 
13
14
 
15
+ class KubernetesResourceInjectionPolicyEnum(str, Enum):
16
+ """
17
+ Device injection policies for Kubernetes workloads.
18
+ """
19
+
20
+ AUTO = "Auto"
21
+ """
22
+ Detect the policy from the target node's allocatable resources.
23
+ """
24
+ ENV = "Env"
25
+ """
26
+ Inject runtime-visible device environment variables without device-plugin requests.
27
+ """
28
+ KDP = "KDP"
29
+ """
30
+ Request device-plugin resources.
31
+ """
32
+
33
+ @classmethod
34
+ def _missing_(cls, value: object) -> KubernetesResourceInjectionPolicyEnum | None:
35
+ if isinstance(value, str):
36
+ for member in cls:
37
+ if member.value.lower() == value.lower():
38
+ return member
39
+ return None
40
+
41
+ def __str__(self) -> str:
42
+ return self.value
43
+
44
+
14
45
  def is_kubelet_socket_accessible(
15
46
  kubelet_endpoint: Path | None = None,
16
47
  ) -> bool:
@@ -79,13 +110,16 @@ def node_has_device_plugin_resources(
79
110
 
80
111
  def get_resource_injection_policy(
81
112
  probe_node_allocatable: Callable[[], Mapping[str, Any] | None] | None = None,
113
+ *,
114
+ policy: KubernetesResourceInjectionPolicyEnum | None = None,
82
115
  ) -> Literal["env", "kdp"]:
83
116
  """
84
117
  Get the resource injection policy (in lowercase) for the deployer.
85
118
 
86
- An explicit policy always wins. Under "auto" the decision belongs to the
87
- cluster, not to the process doing the deploying: the Kubernetes deployer
88
- orchestrates remotely, so whether *it* can reach a kubelet socket says
119
+ A workload policy overrides the environment setting. Under "auto" the
120
+ decision belongs to the cluster, not to the process doing the deploying:
121
+ the Kubernetes deployer orchestrates remotely, so whether *it* can reach
122
+ a kubelet socket says
89
123
  nothing about whether the *target* node runs a device plugin. So the probe
90
124
  reads that node's allocatable resources and looks for a device-plugin
91
125
  resource family there.
@@ -99,14 +133,29 @@ def get_resource_injection_policy(
99
133
  probe_node_allocatable:
100
134
  Called only under the "auto" policy, to read the target node's
101
135
  allocatable resources. Returns None when the node cannot be read.
136
+ policy:
137
+ Workload policy override. None inherits the environment setting;
138
+ Auto probes the node even if the environment selects Env or KDP.
139
+
140
+ Raises:
141
+ ValueError:
142
+ If the policy is not Auto, Env or KDP.
102
143
 
103
144
  Returns:
104
145
  The resource injection policy.
105
146
 
106
147
  """
107
- policy = envs.GPUSTACK_RUNTIME_KUBERNETES_RESOURCE_INJECTION_POLICY.lower()
108
- if policy != "auto":
109
- return policy
148
+ if policy is None:
149
+ policy = envs.GPUSTACK_RUNTIME_KUBERNETES_RESOURCE_INJECTION_POLICY
150
+ try:
151
+ policy = KubernetesResourceInjectionPolicyEnum(policy)
152
+ except ValueError as e:
153
+ msg = f"Invalid resource injection policy '{policy}'"
154
+ raise ValueError(msg) from e
155
+ if policy == KubernetesResourceInjectionPolicyEnum.ENV:
156
+ return "env"
157
+ if policy == KubernetesResourceInjectionPolicyEnum.KDP:
158
+ return "kdp"
110
159
 
111
160
  if probe_node_allocatable is None:
112
161
  return "kdp"
@@ -142,6 +191,7 @@ def cdi_kind_to_kdp_resource(
142
191
 
143
192
 
144
193
  __all__ = [
194
+ "KubernetesResourceInjectionPolicyEnum",
145
195
  "cdi_kind_to_kdp_resource",
146
196
  "get_resource_injection_policy",
147
197
  "is_kubelet_socket_accessible",
@@ -7,12 +7,14 @@ import math
7
7
  import os
8
8
  import re
9
9
  import time
10
+ from copy import copy
10
11
  from dataclasses import dataclass, field
11
12
  from datetime import datetime, timezone
12
13
  from decimal import Decimal
13
14
  from enum import Enum
14
15
  from pathlib import Path
15
- from typing import TYPE_CHECKING
16
+ from threading import Lock
17
+ from typing import TYPE_CHECKING, Literal
16
18
 
17
19
  import kubernetes
18
20
  import kubernetes.stream.ws_client
@@ -49,11 +51,16 @@ from .__utils__ import (
49
51
  sensitive_env_var,
50
52
  validate_rfc1123_domain_name,
51
53
  )
52
- from .k8s.devicemanager import get_resource_injection_policy
54
+ from .k8s.devicemanager import (
55
+ KubernetesResourceInjectionPolicyEnum,
56
+ get_resource_injection_policy,
57
+ )
53
58
 
54
59
  if TYPE_CHECKING:
55
60
  from collections.abc import Callable, Generator
56
61
 
62
+ from .__types__ import DevicesMaterial
63
+
57
64
  logger = logging.getLogger(__name__)
58
65
  clogger = logger.getChild("conversion")
59
66
 
@@ -117,6 +124,9 @@ class KubernetesWorkloadPlan(WorkloadPlan):
117
124
  Domain suffix for the cluster. Default is "cluster.local".
118
125
  service_type (KubernetesWorkloadServiceTypeEnum):
119
126
  Service type for the workload. Default is CLUSTER_IP.
127
+ resource_injection_policy (KubernetesResourceInjectionPolicyEnum | None):
128
+ Workload override for GPUSTACK_RUNTIME_KUBERNETES_RESOURCE_INJECTION_POLICY.
129
+ None inherits the environment setting. Auto probes the target node.
120
130
  namespace (str | None):
121
131
  Namespace of the workload.
122
132
  name (str):
@@ -159,6 +169,16 @@ class KubernetesWorkloadPlan(WorkloadPlan):
159
169
  Service type for the workload.
160
170
  """
161
171
 
172
+ resource_injection_policy: KubernetesResourceInjectionPolicyEnum | None = None
173
+ """
174
+ Device injection policy for this workload. None inherits
175
+ GPUSTACK_RUNTIME_KUBERNETES_RESOURCE_INJECTION_POLICY (default Auto).
176
+ Env uses runtime-visible device environment variables; KDP requests
177
+ device-plugin resources; Auto detects the policy from the target node.
178
+ This setting does not change the environment or other workloads.
179
+ Env injection of all devices uses the runtime's privileged container path.
180
+ """
181
+
162
182
  def validate_and_default(self):
163
183
  """
164
184
  Validate and set defaults for the workload plan.
@@ -168,6 +188,15 @@ class KubernetesWorkloadPlan(WorkloadPlan):
168
188
  If the workload plan is invalid.
169
189
 
170
190
  """
191
+ if self.resource_injection_policy is not None:
192
+ try:
193
+ self.resource_injection_policy = KubernetesResourceInjectionPolicyEnum(
194
+ self.resource_injection_policy,
195
+ )
196
+ except ValueError as e:
197
+ msg = f"Invalid resource injection policy '{self.resource_injection_policy}'"
198
+ raise ValueError(msg) from e
199
+
171
200
  if self.labels is None:
172
201
  self.labels = {}
173
202
  if self.containers is None:
@@ -1153,6 +1182,9 @@ class KubernetesDeployer(EndoscopicDeployer):
1153
1182
  self._node_name = node.metadata.name
1154
1183
  return node.status.allocatable or {}
1155
1184
 
1185
+ _resource_injection_policy: Literal["env", "kdp"] | None = None
1186
+ """Resolved policy on the deployment instance dedicated to one workload."""
1187
+
1156
1188
  def _resolve_resource_injection_policy(self) -> str:
1157
1189
  """
1158
1190
  Resolve the resource injection policy for this deployer, probing the
@@ -1162,6 +1194,8 @@ class KubernetesDeployer(EndoscopicDeployer):
1162
1194
  The resource injection policy.
1163
1195
 
1164
1196
  """
1197
+ if self._resource_injection_policy is not None:
1198
+ return self._resource_injection_policy
1165
1199
  return get_resource_injection_policy(self._probe_node_allocatable)
1166
1200
 
1167
1201
  def _get_default_node_name(self) -> str:
@@ -1806,14 +1840,33 @@ class KubernetesDeployer(EndoscopicDeployer):
1806
1840
  self._client = self._get_client()
1807
1841
  self._node_name = envs.GPUSTACK_RUNTIME_KUBERNETES_NODE_NAME
1808
1842
  self._runtime_uuid_values_allowed: bool | None = None
1843
+ self._deployment_lock = Lock()
1844
+ self._materials_cache: dict[str, dict[str, DevicesMaterial]] = {}
1845
+ self._materials_locks = {policy: Lock() for policy in ("env", "kdp")}
1846
+
1847
+ def _prepare(self):
1848
+ """
1849
+ Reuse device materials built for the same resolved injection policy.
1850
+ """
1851
+ if self._materials is not None:
1852
+ return
1853
+ policy = self._resolve_resource_injection_policy()
1854
+ with self._materials_locks[policy]:
1855
+ if policy not in self._materials_cache:
1856
+ self._runtime_uuid_values_allowed = policy != "kdp"
1857
+ try:
1858
+ super()._prepare()
1859
+ except Exception:
1860
+ # Incomplete detection must not become a reusable device map.
1861
+ self._materials = None
1862
+ raise
1863
+ self._materials_cache[policy] = self._materials
1864
+ self._materials = self._materials_cache[policy]
1809
1865
 
1810
1866
  @property
1811
1867
  def allowed_runtime_uuid_values(self) -> bool:
1812
- # Resolved once per deployer, unlike the per-Pod resolution the
1813
- # creation path wants: this gates how `_prepare` builds the device
1814
- # materials, which are themselves built once, and it is read there once
1815
- # per manufacturer -- so probing on every read would spend one API call
1816
- # per manufacturer to answer a question already settled.
1868
+ # Device materials and UUID eligibility belong to the same resolved
1869
+ # policy. Workloads with the same policy reuse the device materials.
1817
1870
  if self._runtime_uuid_values_allowed is None:
1818
1871
  self._runtime_uuid_values_allowed = (
1819
1872
  self._resolve_resource_injection_policy() != "kdp"
@@ -2143,25 +2196,40 @@ class KubernetesDeployer(EndoscopicDeployer):
2143
2196
  msg = f"Invalid workload plan type: {type(workload)}"
2144
2197
  raise TypeError(msg)
2145
2198
 
2146
- self._prepare_mirrored_deployment()
2147
-
2148
- if isinstance(workload, WorkloadPlan):
2199
+ if not isinstance(workload, KubernetesWorkloadPlan):
2149
2200
  workload = KubernetesWorkloadPlan(**workload.__dict__)
2150
2201
  workload.validate_and_default()
2202
+
2203
+ # Node selection and mirrored options belong to the registered deployer,
2204
+ # including the node used by later workload listing operations.
2205
+ with self._deployment_lock:
2206
+ self._prepare_mirrored_deployment()
2207
+ deployer: KubernetesDeployer = copy(self)
2208
+
2209
+ # Each workload resolves its policy independently while sharing cached
2210
+ # device materials only with workloads using the same policy.
2211
+ deployer._materials = None
2212
+ deployer._resource_injection_policy = get_resource_injection_policy(
2213
+ deployer._probe_node_allocatable,
2214
+ policy=workload.resource_injection_policy,
2215
+ )
2216
+ deployer._runtime_uuid_values_allowed = (
2217
+ deployer._resource_injection_policy != "kdp"
2218
+ )
2151
2219
  if logger.isEnabledFor(logging.DEBUG):
2152
2220
  logger.debug("Creating workload:\n%s", workload.to_yaml())
2153
2221
 
2154
2222
  # Create ephemeral file if needed,
2155
2223
  # (container index, configured path): <actual ConfigMap name>
2156
2224
  ephemeral_filename_mapping: dict[tuple[int, str], str] = (
2157
- self._create_ephemeral_configmaps(workload)
2225
+ deployer._create_ephemeral_configmaps(workload)
2158
2226
  )
2159
2227
 
2160
2228
  # Create Service if needed.
2161
- self._create_service(workload)
2229
+ deployer._create_service(workload)
2162
2230
 
2163
2231
  # Create Pod.
2164
- self._create_pod(
2232
+ deployer._create_pod(
2165
2233
  workload,
2166
2234
  ephemeral_filename_mapping,
2167
2235
  )
@@ -41,7 +41,7 @@ markdown_extensions:
41
41
  extra:
42
42
  generator: false
43
43
 
44
- copyright: Copyright &copy; 2025, GPUStack Contributors
44
+ copyright: Copyright &copy; 2026, GPUStack Contributors
45
45
 
46
46
  nav:
47
47
  - Modules:
@@ -425,7 +425,7 @@ gpustack_runtime/
425
425
  │ ├── __types__.py # Container/Workload{Plan,Status}, Deployer ABC, DevicesMaterial
426
426
  │ ├── docker.py # DockerWorkloadStatus.parse_state
427
427
  │ ├── podman.py
428
- │ ├── kuberentes.py # KubernetesWorkloadStatus.parse_state, Pod/Event reads
428
+ │ ├── kubernetes.py # KubernetesWorkloadStatus.parse_state, Pod/Event reads
429
429
  │ └── cdi/<vendor>.py # CDI spec generation, consumes Device.index/appendix
430
430
  ├── cmds/detector.py # `detect` / `topology` sub-commands
431
431
  └── envs.py # GPUSTACK_RUNTIME_* env surface
@@ -769,14 +769,14 @@ implement `detect_info()`.
769
769
  - [x] **D1 · Pin the device ordering for containers that see every card**
770
770
  Blocked by: None
771
771
  Owns: `gpustack_runtime/deployer/__types__.py`, `gpustack_runtime/deployer/docker.py`,
772
- `gpustack_runtime/deployer/podman.py`, `gpustack_runtime/deployer/kuberentes.py`,
772
+ `gpustack_runtime/deployer/podman.py`, `gpustack_runtime/deployer/kubernetes.py`,
773
773
  `tests/gpustack_runtime/deployer/test_visible_devices_ordering.py`
774
774
  Gate: review
775
775
  Scope: add `Deployer.map_visible_devices_ordering(runtime_envs) -> dict[str, str]` beside the
776
776
  existing `map_backend_visible_devices` / `map_visible_devices_affinities` — it resolves each
777
777
  runtime visible-devices env name to its manufacturer through `get_manufacturer()` and returns
778
778
  `{"CUDA_DEVICE_ORDER": "PCI_BUS_ID"}` when NVIDIA is among them, `{}` otherwise. Call it from all
779
- three deployers' device-request loops (`docker.py`, `podman.py`, `kuberentes.py`), right beside
779
+ three deployers' device-request loops (`docker.py`, `podman.py`, `kubernetes.py`), right beside
780
780
  the existing `if r_v != "all" and privileged:` backend-visible-devices block, under the
781
781
  complementary condition `r_v == "all" or privileged` — the deployers' own resolution of "this
782
782
  container sees every card". Never overwrite a value the container already declares (the
@@ -823,7 +823,7 @@ implement `detect_info()`.
823
823
 
824
824
  - [x] **D5 · Kubernetes: exit status, image-pull failure, Pod Events, RBAC**
825
825
  Blocked by: D2
826
- Owns: `gpustack_runtime/deployer/kuberentes.py`, `deploy/manifests/kubernetes.yaml`,
826
+ Owns: `gpustack_runtime/deployer/kubernetes.py`, `deploy/manifests/kubernetes.yaml`,
827
827
  `tests/gpustack_runtime/deployer/test_kubernetes_status.py`
828
828
  Gate: review
829
829
  Scope: fill the exit list from `container_statuses` / `init_container_statuses`, reading
@@ -9,7 +9,7 @@ import kubernetes.client
9
9
  import pytest
10
10
 
11
11
  from gpustack_runtime.deployer.__types__ import WorkloadStatusStateEnum
12
- from gpustack_runtime.deployer.kuberentes import KubernetesWorkloadStatus
12
+ from gpustack_runtime.deployer.kubernetes import KubernetesWorkloadStatus
13
13
 
14
14
  _REGISTRY_MESSAGE = 'Back-off pulling image "does-not-exist.invalid/x:y"'
15
15
  _EVENT_MESSAGE = (