gpustack-runtime 0.2.2.post7__tar.gz → 0.2.2.post8__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 (135) hide show
  1. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/PKG-INFO +1 -1
  2. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/deploy/manifests/kubernetes.yaml +13 -0
  3. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/_version.py +2 -2
  4. gpustack_runtime-0.2.2.post8/gpustack_runtime/_version_appendix.py +1 -0
  5. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/kuberentes.py +91 -0
  6. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/envs.py +22 -0
  7. gpustack_runtime-0.2.2.post8/tests/gpustack_runtime/deployer/test_runtime_class.py +183 -0
  8. gpustack_runtime-0.2.2.post7/gpustack_runtime/_version_appendix.py +0 -1
  9. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/.codespelldict +0 -0
  10. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/.codespellrc +0 -0
  11. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/.dockerignore +0 -0
  12. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/.gitattributes +0 -0
  13. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/.gitignore +0 -0
  14. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/.pre-commit-config.yaml +0 -0
  15. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/.python-version +0 -0
  16. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/LICENSE +0 -0
  17. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/Makefile +0 -0
  18. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/README.md +0 -0
  19. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/deploy/manifests/docker-compose.yaml +0 -0
  20. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/docs/index.md +0 -0
  21. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/docs/modules/gpustack_runtime.deployer.md +0 -0
  22. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/docs/modules/gpustack_runtime.detector.md +0 -0
  23. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/docs/modules/gpustack_runtime.md +0 -0
  24. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/__init__.py +0 -0
  25. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/__main__.py +0 -0
  26. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/_version.pyi +0 -0
  27. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/cmds/__init__.py +0 -0
  28. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/cmds/__types__.py +0 -0
  29. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/cmds/deployer.py +0 -0
  30. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/cmds/detector.py +0 -0
  31. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/cmds/images.py +0 -0
  32. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/__init__.py +0 -0
  33. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/__patches__.py +0 -0
  34. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/__types__.py +0 -0
  35. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/__utils__.py +0 -0
  36. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/__init__.py +0 -0
  37. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/__types__.py +0 -0
  38. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/__utils__.py +0 -0
  39. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/amd.py +0 -0
  40. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/ascend.py +0 -0
  41. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/hygon.py +0 -0
  42. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/iluvatar.py +0 -0
  43. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/metax.py +0 -0
  44. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/cdi/thead.py +0 -0
  45. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/docker.py +0 -0
  46. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/k8s/devicemanager/__init__.py +0 -0
  47. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/deployer/podman.py +0 -0
  48. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/__init__.py +0 -0
  49. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/__types__.py +0 -0
  50. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/__utils__.py +0 -0
  51. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/amd.py +0 -0
  52. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/ascend.py +0 -0
  53. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/cambricon.py +0 -0
  54. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/hygon.py +0 -0
  55. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/iluvatar.py +0 -0
  56. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/metax.py +0 -0
  57. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/mthreads.py +0 -0
  58. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/nvidia.py +0 -0
  59. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pyamdgpu/__init__.py +0 -0
  60. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pyamdsmi/__init__.py +0 -0
  61. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pydcmi/__init__.py +0 -0
  62. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pyhgml/__init__.py +0 -0
  63. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pyhgml/libhgml.so +0 -0
  64. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pyhgml/libuki.so +0 -0
  65. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pyhsa/__init__.py +0 -0
  66. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pyixml/__init__.py +0 -0
  67. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pymtml/__init__.py +0 -0
  68. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pymxsml/__init__.py +0 -0
  69. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pynvml/__init__.py +0 -0
  70. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/pyrocmsmi/__init__.py +0 -0
  71. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/detector/thead.py +0 -0
  72. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/gpustack_runtime/logging.py +0 -0
  73. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/hatch.toml +0 -0
  74. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/mkdocs.yml +0 -0
  75. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/pack/Dockerfile +0 -0
  76. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/pack/Dockerfile.dummy +0 -0
  77. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/pyproject.toml +0 -0
  78. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/pytest.ini +0 -0
  79. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/ruff.toml +0 -0
  80. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/__init__.py +0 -0
  81. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/test_compare_versions.json +0 -0
  82. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/test_correct_runner_image.json +0 -0
  83. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json.json +0 -0
  84. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json_multiple_jsons.json +0 -0
  85. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json_multiple_yamls.yaml +0 -0
  86. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json_single_json.json +0 -0
  87. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/test_load_yaml_or_json_single_yaml.yaml +0 -0
  88. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/fixtures/test_nginx_entrypoint.sh +0 -0
  89. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/test_privileged.py +0 -0
  90. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/test_utils.py +0 -0
  91. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/deployer/test_workload_status.py +0 -0
  92. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/fixtures/__init__.py +0 -0
  93. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/README.md +0 -0
  94. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_amd_mi300x.json +0 -0
  95. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_amd_mi308x.json +0 -0
  96. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_amd_rx7800xt.json +0 -0
  97. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_ascend_310p3.json +0 -0
  98. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_ascend_910b2.json +0 -0
  99. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_hygon_k100ai.json +0 -0
  100. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_metax_c500.json +0 -0
  101. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_gb10.json +0 -0
  102. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_h100.json +0 -0
  103. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_h100_mig.json +0 -0
  104. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_h200.json +0 -0
  105. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_rtx4080super.json +0 -0
  106. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_rtx4090d.json +0 -0
  107. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_nvidia_rtx5090d.json +0 -0
  108. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/detect_output_thead_ppu.json +0 -0
  109. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_amd_mi300x.json +0 -0
  110. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_amd_mi308x.json +0 -0
  111. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_amd_rx7800xt.json +0 -0
  112. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_ascend_310p3.json +0 -0
  113. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_ascend_910b2.json +0 -0
  114. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_hygon_k100ai.json +0 -0
  115. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_metax_c500.json +0 -0
  116. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_mthreads_s5000.json +0 -0
  117. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_h100.json +0 -0
  118. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_h100_mig.json +0 -0
  119. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_h200.json +0 -0
  120. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_rtx4080super.json +0 -0
  121. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_rtx4090d.json +0 -0
  122. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_nvidia_rtx5090d.json +0 -0
  123. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/samples/topology_output_thead_ppu.json +0 -0
  124. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_amd.py +0 -0
  125. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_ascend.py +0 -0
  126. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_cambricon.py +0 -0
  127. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_detector_utils.py +0 -0
  128. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_hygon.py +0 -0
  129. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_iluvatar.py +0 -0
  130. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_metax.py +0 -0
  131. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_mig_devices.py +0 -0
  132. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_mthreads.py +0 -0
  133. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/tests/gpustack_runtime/detector/test_nvidia.py +0 -0
  134. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/uv.lock +0 -0
  135. {gpustack_runtime-0.2.2.post7 → gpustack_runtime-0.2.2.post8}/uv.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gpustack-runtime
3
- Version: 0.2.2.post7
3
+ Version: 0.2.2.post8
4
4
  Summary: GPUStack Runtime is library for detecting GPU resources and launching GPU workloads.
5
5
  Project-URL: Homepage, https://github.com/gpustack/runtime
6
6
  Project-URL: Bug Tracker, https://github.com/gpustack/gpustack/issues
@@ -25,6 +25,14 @@ rules:
25
25
  - "pods/exec"
26
26
  verbs:
27
27
  - "*"
28
+ # Allow resolving the vendor RuntimeClass (e.g. "ascend", "nvidia") for
29
+ # accelerated workload Pods, see GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_CLASS.
30
+ - apiGroups:
31
+ - "node.k8s.io"
32
+ resources:
33
+ - "runtimeclasses"
34
+ verbs:
35
+ - "get"
28
36
  ---
29
37
  apiVersion: rbac.authorization.k8s.io/v1
30
38
  kind: RoleBinding
@@ -76,6 +84,11 @@ spec:
76
84
  "app.kubernetes.io/name": "gpustack-runtime"
77
85
  spec:
78
86
  # Provide GPU resource request for gpustack-runtime if not using default runtime.
87
+ # The runtimeClassName set here is mirrored to every deployed workload Pod
88
+ # that does not resolve one itself. Usually this is unnecessary: workload
89
+ # Pods requesting device plugin resources automatically adopt the mapped
90
+ # vendor RuntimeClass when it exists in the cluster,
91
+ # see GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_CLASS.
79
92
  #
80
93
  # runtimeClassName: nvidia
81
94
 
@@ -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.2.post7'
31
- __version_tuple__ = version_tuple = (0, 2, 2, 'post7')
30
+ __version__ = version = '0.2.2.post8'
31
+ __version_tuple__ = version_tuple = (0, 2, 2, 'post8')
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 = "cad3f1b"
@@ -338,6 +338,96 @@ def _is_device_plugin_resource(resource_key: str) -> bool:
338
338
  )
339
339
 
340
340
 
341
+ def _match_runtime_class(resource_key: str) -> str:
342
+ """
343
+ Return the RuntimeClass name mapped to the device plugin resource family
344
+ of the given resource key, which matches either a mapped base key
345
+ ("huawei.com/npu") or one of its suffixed variants
346
+ ("huawei.com/npu.sliced", "huawei.com/npu.sliced.units").
347
+ Return an empty string if the key belongs to no mapped family.
348
+ """
349
+ for base_key, runtime_class_name in (
350
+ envs.GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_CLASS or {}
351
+ ).items():
352
+ if resource_key == base_key or resource_key.startswith(f"{base_key}."):
353
+ return runtime_class_name
354
+ return ""
355
+
356
+
357
+ def _resolve_runtime_class_name(
358
+ pod: kubernetes.client.V1Pod,
359
+ client: kubernetes.client.ApiClient,
360
+ ):
361
+ """
362
+ Resolve the RuntimeClass for the Pod from the device plugin resources
363
+ requested by its containers, and set `pod.spec.runtime_class_name`
364
+ when the mapped RuntimeClass object exists in the cluster.
365
+
366
+ A Pod that already names a runtime class is left untouched, and the
367
+ mirrored deployment fill stays the fallback for Pods without any
368
+ mapped device request, so the precedence is:
369
+ explicit > discovered > mirrored.
370
+ """
371
+ if pod.spec.runtime_class_name:
372
+ return
373
+
374
+ # Find the RuntimeClass mapped to the requested device resources,
375
+ # keeping the first match on multi-vendor conflicts.
376
+ runtime_class_name = ""
377
+ for container in (pod.spec.containers or []) + (pod.spec.init_containers or []):
378
+ resources = container.resources
379
+ if not resources or not resources.requests:
380
+ continue
381
+ for r_k in resources.requests:
382
+ matched = _match_runtime_class(r_k)
383
+ if not matched:
384
+ continue
385
+ if runtime_class_name and runtime_class_name != matched:
386
+ logger.warning(
387
+ "Container '%s' requests resource '%s' mapped to RuntimeClass '%s', "
388
+ "but keeping the first matched RuntimeClass '%s'",
389
+ container.name,
390
+ r_k,
391
+ matched,
392
+ runtime_class_name,
393
+ )
394
+ continue
395
+ runtime_class_name = matched
396
+ if not runtime_class_name:
397
+ return
398
+
399
+ # Set the RuntimeClass only if the object exists in the cluster,
400
+ # as naming a missing class makes the kubelet reject the Pod.
401
+ node_api = kubernetes.client.NodeV1Api(client)
402
+ try:
403
+ node_api.read_runtime_class(name=runtime_class_name)
404
+ except kubernetes.client.exceptions.ApiException as e:
405
+ if e.status == 403:
406
+ logger.warning(
407
+ "Workload requests device resources mapped to RuntimeClass '%s', "
408
+ "but the deployer has no permission to read RuntimeClasses, "
409
+ "leaving the Pod runtimeClassName empty",
410
+ runtime_class_name,
411
+ )
412
+ return
413
+ if e.status == 404:
414
+ logger.warning(
415
+ "Workload requests device resources mapped to RuntimeClass '%s', "
416
+ "but that RuntimeClass is not available in the cluster, "
417
+ "leaving the Pod runtimeClassName empty",
418
+ runtime_class_name,
419
+ )
420
+ return
421
+ raise
422
+
423
+ logger.info(
424
+ "Setting Pod runtimeClassName to '%s', "
425
+ "resolved from the requested device resources",
426
+ runtime_class_name,
427
+ )
428
+ pod.spec.runtime_class_name = runtime_class_name
429
+
430
+
341
431
  def _resolve_privileged(container: Container) -> bool:
342
432
  """
343
433
  Resolve whether a container runs privileged.
@@ -1297,6 +1387,7 @@ class KubernetesDeployer(EndoscopicDeployer):
1297
1387
  _apply_instance_type_admission(pod, workload.instance_type)
1298
1388
  _pin_pod_for_kueue(pod, self._node_name)
1299
1389
 
1390
+ _resolve_runtime_class_name(pod, self._client)
1300
1391
  pod = self._mutate_create_pod(pod)
1301
1392
  if envs.GPUSTACK_RUNTIME_DEPLOY_PRINT_CONVERSION:
1302
1393
  clogger.info(
@@ -185,6 +185,17 @@ if TYPE_CHECKING:
185
185
  e.g., `{"nvidia.com/devices": ["CUDA_VISIBLE_DEVICES"], "amd.com/devices": ["ROCR_VISIBLE_DEVICES"]}`.
186
186
  The key is the resource key, and the value is a list of environment variable names.
187
187
  """
188
+ GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_CLASS: dict[str, str] | None = None
189
+ """
190
+ Manual mapping of Kubernetes RuntimeClass names,
191
+ which is used to tell the Kubernetes Deployer which RuntimeClass to run the workload Pod with,
192
+ e.g., `{"nvidia.com/gpu": "nvidia", "huawei.com/npu": "ascend"}`.
193
+ The key is the device plugin base resource key, and the value is the RuntimeClass name.
194
+ During deployment, if any container requests a resource of a mapped family
195
+ (the base key or one of its suffixed variants, e.g., "huawei.com/npu.sliced"),
196
+ and a RuntimeClass object with the mapped name exists in the cluster,
197
+ the workload Pod carries that RuntimeClass name.
198
+ """
188
199
  GPUSTACK_RUNTIME_DEPLOY_RUNTIME_VISIBLE_DEVICES_VALUE_UUID: set[str] | None = None
189
200
  """
190
201
  Apply UUIDs for the given runtime visible devices environment variables.
@@ -538,6 +549,17 @@ variables: dict[str, Callable[[], Any]] = {
538
549
  "alibabacloud.com/devices=alibabacloud.com/ppu;",
539
550
  ),
540
551
  ),
552
+ "GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_CLASS": lambda: to_dict(
553
+ getenv(
554
+ "GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_CLASS",
555
+ "amd.com/gpu=amd;"
556
+ "huawei.com/npu=ascend;"
557
+ "cambricon.com/mlu=cambricon;"
558
+ "iluvatar.com/gpu=iluvatar;"
559
+ "mthreads.com/gpu=mthreads;"
560
+ "nvidia.com/gpu=nvidia;",
561
+ ),
562
+ ),
541
563
  "GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_VISIBLE_DEVICES": lambda: to_dict(
542
564
  getenv(
543
565
  "GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_VISIBLE_DEVICES",
@@ -0,0 +1,183 @@
1
+ import logging
2
+
3
+ import kubernetes
4
+ import pytest
5
+
6
+ from gpustack_runtime import envs
7
+ from gpustack_runtime.deployer.kuberentes import (
8
+ _match_runtime_class,
9
+ _resolve_runtime_class_name,
10
+ )
11
+
12
+
13
+ @pytest.mark.parametrize(
14
+ "name, resource_key, expected",
15
+ [
16
+ ("base key", "huawei.com/npu", "ascend"),
17
+ ("sliced variant", "huawei.com/npu.sliced", "ascend"),
18
+ ("sliced units variant", "huawei.com/npu.sliced.units", "ascend"),
19
+ ("shared variant", "nvidia.com/gpu.shared", "nvidia"),
20
+ (
21
+ "partitioned variant",
22
+ "nvidia.com/gpu.partitioned.mig-1g.20gb",
23
+ "nvidia",
24
+ ),
25
+ ("unmapped base key", "hygon.com/dcu", ""),
26
+ ("unrelated resource", "cpu", ""),
27
+ ("gpustack automap key", "gpustack.ai/devices", ""),
28
+ ("key merely prefixed by a base key", "nvidia.com/gpu-alike", ""),
29
+ ],
30
+ )
31
+ def test_match_runtime_class(name, resource_key, expected):
32
+ actual = _match_runtime_class(resource_key)
33
+ assert actual == expected, f"case {name} expected {expected}, but got {actual}"
34
+
35
+
36
+ def _pod(
37
+ containers_requests: list[dict | None],
38
+ runtime_class_name: str | None = None,
39
+ ) -> kubernetes.client.V1Pod:
40
+ containers = []
41
+ for i, requests in enumerate(containers_requests):
42
+ container = kubernetes.client.V1Container(name=f"container-{i}")
43
+ if requests is not None:
44
+ container.resources = kubernetes.client.V1ResourceRequirements(
45
+ requests=requests,
46
+ limits=requests,
47
+ )
48
+ containers.append(container)
49
+ return kubernetes.client.V1Pod(
50
+ spec=kubernetes.client.V1PodSpec(
51
+ containers=containers,
52
+ runtime_class_name=runtime_class_name,
53
+ ),
54
+ )
55
+
56
+
57
+ def _fake_node_api(monkeypatch, existing: set[str], forbidden: bool = False):
58
+ """
59
+ Patch NodeV1Api so that reading a RuntimeClass succeeds for names in
60
+ `existing`, raises 403 when `forbidden`, and 404 otherwise.
61
+ """
62
+ calls = []
63
+
64
+ class FakeNodeV1Api:
65
+ def __init__(self, client):
66
+ pass
67
+
68
+ def read_runtime_class(self, name):
69
+ calls.append(name)
70
+ if forbidden:
71
+ raise kubernetes.client.exceptions.ApiException(
72
+ status=403,
73
+ reason="Forbidden",
74
+ )
75
+ if name not in existing:
76
+ raise kubernetes.client.exceptions.ApiException(
77
+ status=404,
78
+ reason="Not Found",
79
+ )
80
+ return kubernetes.client.V1RuntimeClass(
81
+ metadata=kubernetes.client.V1ObjectMeta(name=name),
82
+ handler=name,
83
+ )
84
+
85
+ monkeypatch.setattr(kubernetes.client, "NodeV1Api", FakeNodeV1Api)
86
+ return calls
87
+
88
+
89
+ def test_resolve_runtime_class_name_base_key(monkeypatch):
90
+ _fake_node_api(monkeypatch, existing={"nvidia"})
91
+ pod = _pod([{"nvidia.com/gpu": "1"}])
92
+
93
+ _resolve_runtime_class_name(pod, None)
94
+
95
+ assert pod.spec.runtime_class_name == "nvidia"
96
+
97
+
98
+ def test_resolve_runtime_class_name_suffixed_family(monkeypatch):
99
+ _fake_node_api(monkeypatch, existing={"ascend"})
100
+ pod = _pod(
101
+ [
102
+ {
103
+ "huawei.com/npu.sliced": "1",
104
+ "huawei.com/npu.sliced.cores-percentage": "30",
105
+ "huawei.com/npu.sliced.memory-percentage": "20",
106
+ },
107
+ ],
108
+ )
109
+
110
+ _resolve_runtime_class_name(pod, None)
111
+
112
+ assert pod.spec.runtime_class_name == "ascend"
113
+
114
+
115
+ def test_resolve_runtime_class_name_missing_class(monkeypatch, caplog):
116
+ _fake_node_api(monkeypatch, existing=set())
117
+ pod = _pod([{"huawei.com/npu.sliced": "1"}])
118
+
119
+ with caplog.at_level(logging.WARNING):
120
+ _resolve_runtime_class_name(pod, None)
121
+
122
+ assert pod.spec.runtime_class_name is None
123
+ assert "ascend" in caplog.text
124
+
125
+
126
+ def test_resolve_runtime_class_name_forbidden(monkeypatch, caplog):
127
+ _fake_node_api(monkeypatch, existing={"ascend"}, forbidden=True)
128
+ pod = _pod([{"huawei.com/npu.sliced": "1"}])
129
+
130
+ with caplog.at_level(logging.WARNING):
131
+ _resolve_runtime_class_name(pod, None)
132
+
133
+ assert pod.spec.runtime_class_name is None
134
+ assert "ascend" in caplog.text
135
+ assert "permission" in caplog.text
136
+
137
+
138
+ def test_resolve_runtime_class_name_never_overwritten(monkeypatch):
139
+ calls = _fake_node_api(monkeypatch, existing={"ascend"})
140
+ pod = _pod([{"huawei.com/npu.sliced": "1"}], runtime_class_name="custom")
141
+
142
+ _resolve_runtime_class_name(pod, None)
143
+
144
+ assert pod.spec.runtime_class_name == "custom"
145
+ assert not calls
146
+
147
+
148
+ def test_resolve_runtime_class_name_conflict_keeps_first(monkeypatch, caplog):
149
+ _fake_node_api(monkeypatch, existing={"nvidia", "ascend"})
150
+ pod = _pod(
151
+ [
152
+ {"nvidia.com/gpu": "1"},
153
+ {"huawei.com/npu.sliced": "1"},
154
+ ],
155
+ )
156
+
157
+ with caplog.at_level(logging.WARNING):
158
+ _resolve_runtime_class_name(pod, None)
159
+
160
+ assert pod.spec.runtime_class_name == "nvidia"
161
+ assert "ascend" in caplog.text
162
+
163
+
164
+ def test_resolve_runtime_class_name_no_mapped_resources(monkeypatch):
165
+ calls = _fake_node_api(monkeypatch, existing={"nvidia"})
166
+ pod = _pod([{"cpu": "2", "memory": "4Gi"}, None])
167
+
168
+ _resolve_runtime_class_name(pod, None)
169
+
170
+ assert pod.spec.runtime_class_name is None
171
+ assert not calls
172
+
173
+
174
+ def test_default_runtime_class_map():
175
+ mapping = envs.GPUSTACK_RUNTIME_DEPLOY_RESOURCE_KEY_MAP_RUNTIME_CLASS
176
+ assert mapping == {
177
+ "amd.com/gpu": "amd",
178
+ "huawei.com/npu": "ascend",
179
+ "cambricon.com/mlu": "cambricon",
180
+ "iluvatar.com/gpu": "iluvatar",
181
+ "mthreads.com/gpu": "mthreads",
182
+ "nvidia.com/gpu": "nvidia",
183
+ }
@@ -1 +0,0 @@
1
- git_commit = "9147850"