Skip to content

Commit 26da0ea

Browse files
authored
Merge pull request kubernetes#92794 from klueska/upstream-more-tests-get-preferred-allocation
Add more tests for device plugin's GetPreferredAllocation() API
2 parents 429f968 + 26cb650 commit 26da0ea

File tree

2 files changed

+196
-5
lines changed

2 files changed

+196
-5
lines changed

pkg/kubelet/cm/devicemanager/manager.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ func (m *ManagerImpl) devicesToAllocate(podUID, contName, resource string, requi
709709
if err != nil {
710710
return nil, err
711711
}
712-
if allocateRemainingFrom(preferred.Intersection(aligned.Union(allocated))) {
712+
if allocateRemainingFrom(preferred.Intersection(aligned)) {
713713
return allocated, nil
714714
}
715715
// Then fallback to allocate from the aligned set if no preferred list
@@ -730,11 +730,11 @@ func (m *ManagerImpl) devicesToAllocate(podUID, contName, resource string, requi
730730

731731
// Then give the plugin the chance to influence the decision on any
732732
// remaining devices to allocate.
733-
preferred, err := m.callGetPreferredAllocationIfAvailable(podUID, contName, resource, available.Union(devices), devices, required)
733+
preferred, err := m.callGetPreferredAllocationIfAvailable(podUID, contName, resource, available.Union(allocated), allocated, required)
734734
if err != nil {
735735
return nil, err
736736
}
737-
if allocateRemainingFrom(preferred.Intersection(available.Union(allocated))) {
737+
if allocateRemainingFrom(preferred.Intersection(available)) {
738738
return allocated, nil
739739
}
740740

@@ -997,8 +997,10 @@ func (m *ManagerImpl) callGetPreferredAllocationIfAvailable(podUID, contName, re
997997
if err != nil {
998998
return nil, fmt.Errorf("device plugin GetPreferredAllocation rpc failed with err: %v", err)
999999
}
1000-
// TODO: Add metrics support for init RPC
1001-
return sets.NewString(resp.ContainerResponses[0].DeviceIDs...), nil
1000+
if resp != nil && len(resp.ContainerResponses) > 0 {
1001+
return sets.NewString(resp.ContainerResponses[0].DeviceIDs...), nil
1002+
}
1003+
return sets.NewString(), nil
10021004
}
10031005

10041006
// sanitizeNodeAllocatable scans through allocatedDevices in the device manager

pkg/kubelet/cm/devicemanager/topology_hints_test.go

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,3 +791,192 @@ func TestTopologyAlignedAllocation(t *testing.T) {
791791
}
792792
}
793793
}
794+
795+
func TestGetPreferredAllocationParameters(t *testing.T) {
796+
tcases := []struct {
797+
description string
798+
resource string
799+
request int
800+
allDevices []pluginapi.Device
801+
allocatedDevices []string
802+
reusableDevices []string
803+
hint topologymanager.TopologyHint
804+
expectedAvailable []string
805+
expectedMustInclude []string
806+
expectedSize int
807+
}{
808+
{
809+
description: "Request for 1, socket 0, 0 already allocated, 0 reusable",
810+
resource: "resource",
811+
request: 1,
812+
allDevices: []pluginapi.Device{
813+
makeNUMADevice("Dev0", 0),
814+
makeNUMADevice("Dev1", 0),
815+
makeNUMADevice("Dev2", 0),
816+
makeNUMADevice("Dev3", 0),
817+
},
818+
allocatedDevices: []string{},
819+
reusableDevices: []string{},
820+
hint: topologymanager.TopologyHint{
821+
NUMANodeAffinity: makeSocketMask(0),
822+
Preferred: true,
823+
},
824+
expectedAvailable: []string{"Dev0", "Dev1", "Dev2", "Dev3"},
825+
expectedMustInclude: []string{},
826+
expectedSize: 1,
827+
},
828+
{
829+
description: "Request for 4, socket 0, 2 already allocated, 2 reusable",
830+
resource: "resource",
831+
request: 4,
832+
allDevices: []pluginapi.Device{
833+
makeNUMADevice("Dev0", 0),
834+
makeNUMADevice("Dev1", 0),
835+
makeNUMADevice("Dev2", 0),
836+
makeNUMADevice("Dev3", 0),
837+
makeNUMADevice("Dev4", 0),
838+
makeNUMADevice("Dev5", 0),
839+
makeNUMADevice("Dev6", 0),
840+
makeNUMADevice("Dev7", 0),
841+
},
842+
allocatedDevices: []string{"Dev0", "Dev5"},
843+
reusableDevices: []string{"Dev0", "Dev5"},
844+
hint: topologymanager.TopologyHint{
845+
NUMANodeAffinity: makeSocketMask(0),
846+
Preferred: true,
847+
},
848+
expectedAvailable: []string{"Dev0", "Dev1", "Dev2", "Dev3", "Dev4", "Dev5", "Dev6", "Dev7"},
849+
expectedMustInclude: []string{"Dev0", "Dev5"},
850+
expectedSize: 4,
851+
},
852+
{
853+
description: "Request for 4, socket 0, 4 already allocated, 2 reusable",
854+
resource: "resource",
855+
request: 4,
856+
allDevices: []pluginapi.Device{
857+
makeNUMADevice("Dev0", 0),
858+
makeNUMADevice("Dev1", 0),
859+
makeNUMADevice("Dev2", 0),
860+
makeNUMADevice("Dev3", 0),
861+
makeNUMADevice("Dev4", 0),
862+
makeNUMADevice("Dev5", 0),
863+
makeNUMADevice("Dev6", 0),
864+
makeNUMADevice("Dev7", 0),
865+
},
866+
allocatedDevices: []string{"Dev0", "Dev5", "Dev4", "Dev1"},
867+
reusableDevices: []string{"Dev0", "Dev5"},
868+
hint: topologymanager.TopologyHint{
869+
NUMANodeAffinity: makeSocketMask(0),
870+
Preferred: true,
871+
},
872+
expectedAvailable: []string{"Dev0", "Dev2", "Dev3", "Dev5", "Dev6", "Dev7"},
873+
expectedMustInclude: []string{"Dev0", "Dev5"},
874+
expectedSize: 4,
875+
},
876+
{
877+
description: "Request for 6, multisocket, 2 already allocated, 2 reusable",
878+
resource: "resource",
879+
request: 6,
880+
allDevices: []pluginapi.Device{
881+
makeNUMADevice("Dev0", 0),
882+
makeNUMADevice("Dev1", 0),
883+
makeNUMADevice("Dev2", 0),
884+
makeNUMADevice("Dev3", 0),
885+
makeNUMADevice("Dev4", 1),
886+
makeNUMADevice("Dev5", 1),
887+
makeNUMADevice("Dev6", 1),
888+
makeNUMADevice("Dev7", 1),
889+
},
890+
allocatedDevices: []string{"Dev1", "Dev6"},
891+
reusableDevices: []string{"Dev1", "Dev6"},
892+
hint: topologymanager.TopologyHint{
893+
NUMANodeAffinity: makeSocketMask(0),
894+
Preferred: true,
895+
},
896+
expectedAvailable: []string{"Dev0", "Dev1", "Dev2", "Dev3", "Dev4", "Dev5", "Dev6", "Dev7"},
897+
expectedMustInclude: []string{"Dev0", "Dev1", "Dev2", "Dev3", "Dev6"},
898+
expectedSize: 6,
899+
},
900+
{
901+
description: "Request for 6, multisocket, 4 already allocated, 2 reusable",
902+
resource: "resource",
903+
request: 6,
904+
allDevices: []pluginapi.Device{
905+
makeNUMADevice("Dev0", 0),
906+
makeNUMADevice("Dev1", 0),
907+
makeNUMADevice("Dev2", 0),
908+
makeNUMADevice("Dev3", 0),
909+
makeNUMADevice("Dev4", 1),
910+
makeNUMADevice("Dev5", 1),
911+
makeNUMADevice("Dev6", 1),
912+
makeNUMADevice("Dev7", 1),
913+
},
914+
allocatedDevices: []string{"Dev0", "Dev1", "Dev6", "Dev7"},
915+
reusableDevices: []string{"Dev1", "Dev6"},
916+
hint: topologymanager.TopologyHint{
917+
NUMANodeAffinity: makeSocketMask(0),
918+
Preferred: true,
919+
},
920+
expectedAvailable: []string{"Dev1", "Dev2", "Dev3", "Dev4", "Dev5", "Dev6"},
921+
expectedMustInclude: []string{"Dev1", "Dev2", "Dev3", "Dev6"},
922+
expectedSize: 6,
923+
},
924+
}
925+
for _, tc := range tcases {
926+
m := ManagerImpl{
927+
allDevices: make(map[string]map[string]pluginapi.Device),
928+
healthyDevices: make(map[string]sets.String),
929+
allocatedDevices: make(map[string]sets.String),
930+
endpoints: make(map[string]endpointInfo),
931+
podDevices: make(podDevices),
932+
sourcesReady: &sourcesReadyStub{},
933+
activePods: func() []*v1.Pod { return []*v1.Pod{} },
934+
topologyAffinityStore: &mockAffinityStore{tc.hint},
935+
}
936+
937+
m.allDevices[tc.resource] = make(map[string]pluginapi.Device)
938+
m.healthyDevices[tc.resource] = sets.NewString()
939+
for _, d := range tc.allDevices {
940+
m.allDevices[tc.resource][d.ID] = d
941+
m.healthyDevices[tc.resource].Insert(d.ID)
942+
}
943+
944+
m.allocatedDevices[tc.resource] = sets.NewString()
945+
for _, d := range tc.allocatedDevices {
946+
m.allocatedDevices[tc.resource].Insert(d)
947+
}
948+
949+
actualAvailable := []string{}
950+
actualMustInclude := []string{}
951+
actualSize := 0
952+
m.endpoints[tc.resource] = endpointInfo{
953+
e: &MockEndpoint{
954+
getPreferredAllocationFunc: func(available, mustInclude []string, size int) (*pluginapi.PreferredAllocationResponse, error) {
955+
actualAvailable = append(actualAvailable, available...)
956+
actualMustInclude = append(actualMustInclude, mustInclude...)
957+
actualSize = size
958+
return nil, nil
959+
},
960+
},
961+
opts: &pluginapi.DevicePluginOptions{GetPreferredAllocationAvailable: true},
962+
}
963+
964+
_, err := m.devicesToAllocate("podUID", "containerName", tc.resource, tc.request, sets.NewString(tc.reusableDevices...))
965+
if err != nil {
966+
t.Errorf("Unexpected error: %v", err)
967+
continue
968+
}
969+
970+
if !sets.NewString(actualAvailable...).Equal(sets.NewString(tc.expectedAvailable...)) {
971+
t.Errorf("%v. expected available: %v but got: %v", tc.description, tc.expectedAvailable, actualAvailable)
972+
}
973+
974+
if !sets.NewString(actualAvailable...).Equal(sets.NewString(tc.expectedAvailable...)) {
975+
t.Errorf("%v. expected mustInclude: %v but got: %v", tc.description, tc.expectedMustInclude, actualMustInclude)
976+
}
977+
978+
if actualSize != tc.expectedSize {
979+
t.Errorf("%v. expected size: %v but got: %v", tc.description, tc.expectedSize, actualSize)
980+
}
981+
}
982+
}

0 commit comments

Comments
 (0)