Add Allocate() call to TopologyManager's HintProvider interface

Having this interface allows us to perform a tight loop of:

    for each container {
        containerHints = {}
        for each provider {
	    containerHints[provider] = provider.GatherHints(container)
        }

        containerHints.MergeAndPublish()

        for each provider {
	    provider.Allocate(container)
        }
    }

With this in place we can now be sure that the hints gathered in one
iteration of the loop always consider the allocations made in the
previous.
This commit is contained in:
Kevin Klues 2020-02-02 21:37:06 +00:00 committed by nolancon
parent a3f099ea4d
commit 9e4ee5ecc3
2 changed files with 37 additions and 5 deletions

View File

@ -77,6 +77,10 @@ type HintProvider interface {
// a consensus "best" hint. The hint providers may subsequently query the // a consensus "best" hint. The hint providers may subsequently query the
// topology manager to influence actual resource assignment. // topology manager to influence actual resource assignment.
GetTopologyHints(pod *v1.Pod, container *v1.Container) map[string][]TopologyHint GetTopologyHints(pod *v1.Pod, container *v1.Container) map[string][]TopologyHint
// Allocate triggers resource allocation to occur on the HintProvider after
// all hints have been gathered and the aggregated Hint is available via a
// call to Store.GetAffinity().
Allocate(pod *v1.Pod, container *v1.Container) error
} }
//Store interface is to allow Hint Providers to retrieve pod affinity //Store interface is to allow Hint Providers to retrieve pod affinity
@ -176,6 +180,16 @@ func (m *manager) accumulateProvidersHints(pod *v1.Pod, container *v1.Container)
return providersHints return providersHints
} }
func (m *manager) allocateAlignedResources(pod *v1.Pod, container *v1.Container) error {
for _, provider := range m.hintProviders {
err := provider.Allocate(pod, container)
if err != nil {
return err
}
}
return nil
}
// Collect Hints from hint providers and pass to policy to retrieve the best one. // Collect Hints from hint providers and pass to policy to retrieve the best one.
func (m *manager) calculateAffinity(pod *v1.Pod, container *v1.Container) (TopologyHint, bool) { func (m *manager) calculateAffinity(pod *v1.Pod, container *v1.Container) (TopologyHint, bool) {
providersHints := m.accumulateProvidersHints(pod, container) providersHints := m.accumulateProvidersHints(pod, container)
@ -216,7 +230,6 @@ func (m *manager) Admit(attrs *lifecycle.PodAdmitAttributes) lifecycle.PodAdmitR
klog.Infof("[topologymanager] Topology Admit Handler") klog.Infof("[topologymanager] Topology Admit Handler")
pod := attrs.Pod pod := attrs.Pod
hints := make(map[string]TopologyHint)
for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) { for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) {
result, admit := m.calculateAffinity(pod, &container) result, admit := m.calculateAffinity(pod, &container)
@ -227,11 +240,22 @@ func (m *manager) Admit(attrs *lifecycle.PodAdmitAttributes) lifecycle.PodAdmitR
Admit: false, Admit: false,
} }
} }
hints[container.Name] = result
}
m.podTopologyHints[string(pod.UID)] = hints klog.Infof("[topologymanager] Topology Affinity for (pod: %v container: %v): %v", pod.UID, container.Name, result)
klog.Infof("[topologymanager] Topology Affinity for Pod: %v are %v", pod.UID, m.podTopologyHints[string(pod.UID)]) if m.podTopologyHints[string(pod.UID)] == nil {
m.podTopologyHints[string(pod.UID)] = make(map[string]TopologyHint)
}
m.podTopologyHints[string(pod.UID)][container.Name] = result
err := m.allocateAlignedResources(pod, &container)
if err != nil {
return lifecycle.PodAdmitResult{
Message: fmt.Sprintf("Allocate failed due to %v, which is unexpected", err),
Reason: "UnexpectedAdmissionError",
Admit: false,
}
}
}
return lifecycle.PodAdmitResult{Admit: true} return lifecycle.PodAdmitResult{Admit: true}
} }

View File

@ -75,12 +75,20 @@ func TestNewManager(t *testing.T) {
type mockHintProvider struct { type mockHintProvider struct {
th map[string][]TopologyHint th map[string][]TopologyHint
//TODO: Add this field and add some tests to make sure things error out
//appropriately on allocation errors.
//allocateError error
} }
func (m *mockHintProvider) GetTopologyHints(pod *v1.Pod, container *v1.Container) map[string][]TopologyHint { func (m *mockHintProvider) GetTopologyHints(pod *v1.Pod, container *v1.Container) map[string][]TopologyHint {
return m.th return m.th
} }
func (m *mockHintProvider) Allocate(pod *v1.Pod, container *v1.Container) error {
//return allocateError
return nil
}
func TestGetAffinity(t *testing.T) { func TestGetAffinity(t *testing.T) {
tcases := []struct { tcases := []struct {
name string name string