diff --git a/README.md b/README.md index b285d9c..7f30258 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,9 @@ To exclusively use an entire card or request multiple cards, you only need to se ### Usage in HAMi -**How HAMi chooses soft vs legacy vNPU:** The device plugin applies **soft slicing** (`libvnpu` / `hami-vnpu-core` mounts and environment) **only** when the Pod sets `huawei.com/vnpu-mode: hami-core`. Pods **without** this annotation still follow the **original vNPU** path (virtualization templates and `ASCEND_VNPU_SPECS`). These two paths are different. If your cluster effectively has **only** soft-slicing–oriented Ascend capacity (for example every node is configured for `hami-vnpu-core` and workloads are expected to use soft slicing), Pods that **omit** `vnpu-mode=hami-core` may remain **Pending** because they still request the legacy vNPU allocation model, which may not match what those nodes expose or how the scheduler pairs Pods to nodes. +**How HAMi chooses soft vs legacy vNPU:** +- A Pod that sets `huawei.com/vnpu-mode: hami-core` always uses **soft slicing** and is scheduled only onto hami-core-capable nodes. +- A Pod that **omits** the annotation is **mode-agnostic**: it may be scheduled onto either a template node or a hami-core node, and its effective mode **follows the node**. On a hami-core node the device plugin applies soft slicing (`libvnpu` / `hami-vnpu-core` mounts and environment); on a template node it uses the original vNPU path (`ASCEND_VNPU_SPECS`). The plugin resolves this from the node's `hami-vnpu-core` setting (`IsHamiVnpuCore()`), so annotation-less Pods no longer remain Pending on hami-core-only clusters. ```yaml ... diff --git a/internal/server/allocate.go b/internal/server/allocate.go index 5028895..429b38f 100644 --- a/internal/server/allocate.go +++ b/internal/server/allocate.go @@ -66,8 +66,9 @@ func (ps *PluginServer) buildContainerAllocateResponse(pod *v1.Pod, ctrName stri resp.Envs["ASCEND_VISIBLE_DEVICES"] = ascendVisibleDevices vnpuMode := pod.Annotations[VNPUModeAnnotation] - klog.V(4).Infof("Pod %s vnpu mode: %s", pod.Name, vnpuMode) - if vnpuMode == VNPUModeHamiCore { + effectiveHamiCore := vnpuMode == VNPUModeHamiCore || (vnpuMode == "" && ps.mgr.IsHamiVnpuCore()) + klog.V(4).Infof("Pod %s vnpu mode: %q, effectiveHamiCore: %v", pod.Name, vnpuMode, effectiveHamiCore) + if effectiveHamiCore { // 1. Handle volume mount injection var mounts []*v1beta1.Mount // A.Huawei driver and SMI toolchain (Read-Only) diff --git a/internal/server/util_test.go b/internal/server/util_test.go index 7a853f9..58c885a 100644 --- a/internal/server/util_test.go +++ b/internal/server/util_test.go @@ -422,6 +422,79 @@ func TestBuildContainerAllocateResponse(t *testing.T) { }, }, }, + { + name: "NoAnnotation_NodeHamiCore_FollowsNode", + setup: func() (*PluginServer, CleanupFunc) { + return &PluginServer{ + mgr: &FakeManager{ + GetDeviceByUUIDFunc: func(uuid string) *manager.Device { + return &manager.Device{UUID: "uuid1", PhyID: 3} + }, + IsHamiVnpuCoreFunc: func() bool { return true }, + }, + allocAnno: allocAnno, + }, func() {} + }, + args: buildContainerAllocateResponseArgs{ + pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}, + containerDevs: device.ContainerDevices{cd("uuid1", "Ascend910", 1024, 4)}, + rtInfoLookup: func() map[string]RuntimeInfo { + mem := int64(8738) + core := int32(4) + return map[string]RuntimeInfo{ + "uuid1": {UUID: "uuid1", Temp: "vir08", Memory: &mem, Core: &core}, + } + }(), + }, + want: buildContainerAllocateResponseWant{ + envs: map[string]string{ + "ASCEND_VISIBLE_DEVICES": "3", + "NPU_MEM_QUOTA": "8738", + "NPU_PRIORITY": "4", + "NPU_GLOBAL_SHM_PATH": "/hami-shared-region/3_global_registry", + }, + mounts: []*v1beta1.Mount{ + {HostPath: "/usr/local/bin/npu-smi", ContainerPath: "/usr/local/bin/npu-smi", ReadOnly: true}, + {HostPath: "/etc/ascend_install.info", ContainerPath: "/etc/ascend_install.info", ReadOnly: true}, + {HostPath: "/usr/local/Ascend/driver/lib64/driver", ContainerPath: "/usr/local/Ascend/driver/lib64/driver", ReadOnly: true}, + {HostPath: "/usr/local/Ascend/driver/version.info", ContainerPath: "/usr/local/Ascend/driver/version.info", ReadOnly: true}, + {HostPath: "/usr/local/hami-vnpu-core", ContainerPath: "/hami-vnpu-core", ReadOnly: true}, + {HostPath: "/usr/local/hami-vnpu-core/ld.so.preload", ContainerPath: "/etc/ld.so.preload", ReadOnly: true}, + {HostPath: "/usr/local/hami-shared-region", ContainerPath: "/hami-shared-region", ReadOnly: false}, + }, + }, + }, + { + name: "NoAnnotation_NodeTemplate_FollowsNode", + setup: func() (*PluginServer, CleanupFunc) { + return &PluginServer{ + mgr: &FakeManager{ + GetDeviceByUUIDFunc: func(uuid string) *manager.Device { + return &manager.Device{UUID: "uuid1", PhyID: 3} + }, + IsHamiVnpuCoreFunc: func() bool { return false }, + }, + allocAnno: allocAnno, + }, func() {} + }, + args: buildContainerAllocateResponseArgs{ + pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}}}, + containerDevs: device.ContainerDevices{cd("uuid1", "Ascend910", 1024, 4)}, + rtInfoLookup: func() map[string]RuntimeInfo { + mem := int64(8738) + core := int32(0) + return map[string]RuntimeInfo{ + "uuid1": {UUID: "uuid1", Temp: "vir08", Memory: &mem, Core: &core}, + } + }(), + }, + want: buildContainerAllocateResponseWant{ + envs: map[string]string{ + "ASCEND_VISIBLE_DEVICES": "3", + "ASCEND_VNPU_SPECS": "vir08", + }, + }, + }, { name: "NonHamiCore_EmptyTemp", setup: func() (*PluginServer, CleanupFunc) {