Ensure devicemanager TopologyHints are regenerated after kubelet restart
This patch also includes test to make sure the newly added logic works as expected.
This commit is contained in:
		@@ -60,6 +60,7 @@ go_test(
 | 
				
			|||||||
        "//staging/src/k8s.io/api/core/v1:go_default_library",
 | 
					        "//staging/src/k8s.io/api/core/v1:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
 | 
				
			||||||
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,21 @@ func (m *ManagerImpl) GetTopologyHints(pod v1.Pod, container v1.Container) map[s
 | 
				
			|||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Short circuit to regenerate the same hints if there are already
 | 
				
			||||||
 | 
								// devices allocated to the Container. This might happen after a
 | 
				
			||||||
 | 
								// kubelet restart, for example.
 | 
				
			||||||
 | 
								allocated := m.podDevices.containerDevices(string(pod.UID), container.Name, resource)
 | 
				
			||||||
 | 
								if allocated.Len() > 0 {
 | 
				
			||||||
 | 
									if allocated.Len() != requested {
 | 
				
			||||||
 | 
										klog.Errorf("[devicemanager] Resource '%v' already allocated to (pod %v, container %v) with different number than request: requested: %d, allocated: %d", resource, string(pod.UID), container.Name, requested, allocated.Len())
 | 
				
			||||||
 | 
										deviceHints[resource] = []topologymanager.TopologyHint{}
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									klog.Infof("[devicemanager] Regenerating TopologyHints for resource '%v' already allocated to (pod %v, container %v)", resource, string(pod.UID), container.Name)
 | 
				
			||||||
 | 
									deviceHints[resource] = m.generateDeviceTopologyHints(resource, allocated, requested)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Get the list of available devices, for which TopologyHints should be generated.
 | 
								// Get the list of available devices, for which TopologyHints should be generated.
 | 
				
			||||||
			available := m.getAvailableDevices(resource)
 | 
								available := m.getAvailableDevices(resource)
 | 
				
			||||||
			if available.Len() < requested {
 | 
								if available.Len() < requested {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						"k8s.io/apimachinery/pkg/api/resource"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1"
 | 
						pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager"
 | 
						"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager"
 | 
				
			||||||
@@ -52,13 +53,17 @@ func makeSocketMask(sockets ...int) bitmask.BitMask {
 | 
				
			|||||||
func TestGetTopologyHints(t *testing.T) {
 | 
					func TestGetTopologyHints(t *testing.T) {
 | 
				
			||||||
	tcases := []struct {
 | 
						tcases := []struct {
 | 
				
			||||||
		description      string
 | 
							description      string
 | 
				
			||||||
 | 
							podUID           string
 | 
				
			||||||
 | 
							containerName    string
 | 
				
			||||||
		request          map[string]string
 | 
							request          map[string]string
 | 
				
			||||||
		devices          map[string][]pluginapi.Device
 | 
							devices          map[string][]pluginapi.Device
 | 
				
			||||||
		allocatedDevices map[string][]string
 | 
							allocatedDevices map[string]map[string]map[string][]string
 | 
				
			||||||
		expectedHints    map[string][]topologymanager.TopologyHint
 | 
							expectedHints    map[string][]topologymanager.TopologyHint
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:   "Single Request, no alignment",
 | 
								description:   "Single Request, no alignment",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
			request: map[string]string{
 | 
								request: map[string]string{
 | 
				
			||||||
				"testdevice": "1",
 | 
									"testdevice": "1",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -74,6 +79,8 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:   "Single Request, only one with alignment",
 | 
								description:   "Single Request, only one with alignment",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
			request: map[string]string{
 | 
								request: map[string]string{
 | 
				
			||||||
				"testdevice": "1",
 | 
									"testdevice": "1",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -98,6 +105,8 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:   "Single Request, one device per socket",
 | 
								description:   "Single Request, one device per socket",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
			request: map[string]string{
 | 
								request: map[string]string{
 | 
				
			||||||
				"testdevice": "1",
 | 
									"testdevice": "1",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -126,6 +135,8 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:   "Request for 2, one device per socket",
 | 
								description:   "Request for 2, one device per socket",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
			request: map[string]string{
 | 
								request: map[string]string{
 | 
				
			||||||
				"testdevice": "2",
 | 
									"testdevice": "2",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -146,6 +157,8 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:   "Request for 2, 2 devices per socket",
 | 
								description:   "Request for 2, 2 devices per socket",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
			request: map[string]string{
 | 
								request: map[string]string{
 | 
				
			||||||
				"testdevice": "2",
 | 
									"testdevice": "2",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -176,6 +189,8 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:   "Request for 2, optimal on 1 NUMA node, forced cross-NUMA",
 | 
								description:   "Request for 2, optimal on 1 NUMA node, forced cross-NUMA",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
			request: map[string]string{
 | 
								request: map[string]string{
 | 
				
			||||||
				"testdevice": "2",
 | 
									"testdevice": "2",
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@@ -187,9 +202,13 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
					makeNUMADevice("Dev4", 1),
 | 
										makeNUMADevice("Dev4", 1),
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			allocatedDevices: map[string][]string{
 | 
								allocatedDevices: map[string]map[string]map[string][]string{
 | 
				
			||||||
 | 
									"fakePod": {
 | 
				
			||||||
 | 
										"fakeOtherContainer": {
 | 
				
			||||||
						"testdevice": {"Dev1", "Dev2"},
 | 
											"testdevice": {"Dev1", "Dev2"},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			expectedHints: map[string][]topologymanager.TopologyHint{
 | 
								expectedHints: map[string][]topologymanager.TopologyHint{
 | 
				
			||||||
				"testdevice": {
 | 
									"testdevice": {
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
@@ -201,6 +220,8 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			description:   "2 device types, mixed configuration",
 | 
								description:   "2 device types, mixed configuration",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
			request: map[string]string{
 | 
								request: map[string]string{
 | 
				
			||||||
				"testdevice1": "2",
 | 
									"testdevice1": "2",
 | 
				
			||||||
				"testdevice2": "1",
 | 
									"testdevice2": "1",
 | 
				
			||||||
@@ -243,6 +264,110 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description:   "Single device type, more requested than available",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
 | 
								request: map[string]string{
 | 
				
			||||||
 | 
									"testdevice": "6",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								devices: map[string][]pluginapi.Device{
 | 
				
			||||||
 | 
									"testdevice": {
 | 
				
			||||||
 | 
										makeNUMADevice("Dev1", 0),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev2", 0),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev3", 1),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev4", 1),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedHints: map[string][]topologymanager.TopologyHint{
 | 
				
			||||||
 | 
									"testdevice": {},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description:   "Single device type, all already allocated to container",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
 | 
								request: map[string]string{
 | 
				
			||||||
 | 
									"testdevice": "2",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								devices: map[string][]pluginapi.Device{
 | 
				
			||||||
 | 
									"testdevice": {
 | 
				
			||||||
 | 
										makeNUMADevice("Dev1", 0),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev2", 0),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								allocatedDevices: map[string]map[string]map[string][]string{
 | 
				
			||||||
 | 
									"fakePod": {
 | 
				
			||||||
 | 
										"fakeContainer": {
 | 
				
			||||||
 | 
											"testdevice": {"Dev1", "Dev2"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedHints: map[string][]topologymanager.TopologyHint{
 | 
				
			||||||
 | 
									"testdevice": {
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											NUMANodeAffinity: makeSocketMask(0),
 | 
				
			||||||
 | 
											Preferred:        true,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											NUMANodeAffinity: makeSocketMask(0, 1),
 | 
				
			||||||
 | 
											Preferred:        false,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description:   "Single device type, less already allocated to container than requested",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
 | 
								request: map[string]string{
 | 
				
			||||||
 | 
									"testdevice": "4",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								devices: map[string][]pluginapi.Device{
 | 
				
			||||||
 | 
									"testdevice": {
 | 
				
			||||||
 | 
										makeNUMADevice("Dev1", 0),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev2", 0),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev3", 1),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev4", 1),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								allocatedDevices: map[string]map[string]map[string][]string{
 | 
				
			||||||
 | 
									"fakePod": {
 | 
				
			||||||
 | 
										"fakeContainer": {
 | 
				
			||||||
 | 
											"testdevice": {"Dev1", "Dev2"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedHints: map[string][]topologymanager.TopologyHint{
 | 
				
			||||||
 | 
									"testdevice": {},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description:   "Single device type, more already allocated to container than requested",
 | 
				
			||||||
 | 
								podUID:        "fakePod",
 | 
				
			||||||
 | 
								containerName: "fakeContainer",
 | 
				
			||||||
 | 
								request: map[string]string{
 | 
				
			||||||
 | 
									"testdevice": "2",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								devices: map[string][]pluginapi.Device{
 | 
				
			||||||
 | 
									"testdevice": {
 | 
				
			||||||
 | 
										makeNUMADevice("Dev1", 0),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev2", 0),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev3", 1),
 | 
				
			||||||
 | 
										makeNUMADevice("Dev4", 1),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								allocatedDevices: map[string]map[string]map[string][]string{
 | 
				
			||||||
 | 
									"fakePod": {
 | 
				
			||||||
 | 
										"fakeContainer": {
 | 
				
			||||||
 | 
											"testdevice": {"Dev1", "Dev2", "Dev3", "Dev4"},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedHints: map[string][]topologymanager.TopologyHint{
 | 
				
			||||||
 | 
									"testdevice": {},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tc := range tcases {
 | 
						for _, tc := range tcases {
 | 
				
			||||||
@@ -252,6 +377,8 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pod := makePod(resourceList)
 | 
							pod := makePod(resourceList)
 | 
				
			||||||
 | 
							pod.UID = types.UID(tc.podUID)
 | 
				
			||||||
 | 
							pod.Spec.Containers[0].Name = tc.containerName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m := ManagerImpl{
 | 
							m := ManagerImpl{
 | 
				
			||||||
			allDevices:       make(map[string]map[string]pluginapi.Device),
 | 
								allDevices:       make(map[string]map[string]pluginapi.Device),
 | 
				
			||||||
@@ -259,7 +386,7 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
			allocatedDevices: make(map[string]sets.String),
 | 
								allocatedDevices: make(map[string]sets.String),
 | 
				
			||||||
			podDevices:       make(podDevices),
 | 
								podDevices:       make(podDevices),
 | 
				
			||||||
			sourcesReady:     &sourcesReadyStub{},
 | 
								sourcesReady:     &sourcesReadyStub{},
 | 
				
			||||||
			activePods:       func() []*v1.Pod { return []*v1.Pod{} },
 | 
								activePods:       func() []*v1.Pod { return []*v1.Pod{pod} },
 | 
				
			||||||
			numaNodes:        []int{0, 1},
 | 
								numaNodes:        []int{0, 1},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -273,13 +400,18 @@ func TestGetTopologyHints(t *testing.T) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for r := range tc.allocatedDevices {
 | 
							for p := range tc.allocatedDevices {
 | 
				
			||||||
			m.allocatedDevices[r] = sets.NewString()
 | 
								for c := range tc.allocatedDevices[p] {
 | 
				
			||||||
 | 
									for r, devices := range tc.allocatedDevices[p][c] {
 | 
				
			||||||
 | 
										m.podDevices.insert(p, c, r, sets.NewString(devices...), nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for _, d := range tc.allocatedDevices[r] {
 | 
										m.allocatedDevices[r] = sets.NewString()
 | 
				
			||||||
 | 
										for _, d := range devices {
 | 
				
			||||||
						m.allocatedDevices[r].Insert(d)
 | 
											m.allocatedDevices[r].Insert(d)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		hints := m.GetTopologyHints(*pod, pod.Spec.Containers[0])
 | 
							hints := m.GetTopologyHints(*pod, pod.Spec.Containers[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user