1/* 2Copyright 2020 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package topologymanager 18 19import ( 20 "sync" 21 22 "k8s.io/api/core/v1" 23 "k8s.io/klog/v2" 24 "k8s.io/kubernetes/pkg/kubelet/cm/admission" 25 "k8s.io/kubernetes/pkg/kubelet/cm/containermap" 26 "k8s.io/kubernetes/pkg/kubelet/lifecycle" 27) 28 29const ( 30 // containerTopologyScope specifies the TopologyManagerScope per container. 31 containerTopologyScope = "container" 32 // podTopologyScope specifies the TopologyManagerScope per pod. 33 podTopologyScope = "pod" 34) 35 36type podTopologyHints map[string]map[string]TopologyHint 37 38// Scope interface for Topology Manager 39type Scope interface { 40 Name() string 41 Admit(pod *v1.Pod) lifecycle.PodAdmitResult 42 // AddHintProvider adds a hint provider to manager to indicate the hint provider 43 // wants to be consoluted with when making topology hints 44 AddHintProvider(h HintProvider) 45 // AddContainer adds pod to Manager for tracking 46 AddContainer(pod *v1.Pod, container *v1.Container, containerID string) 47 // RemoveContainer removes pod from Manager tracking 48 RemoveContainer(containerID string) error 49 // Store is the interface for storing pod topology hints 50 Store 51} 52 53type scope struct { 54 mutex sync.Mutex 55 name string 56 // Mapping of a Pods mapping of Containers and their TopologyHints 57 // Indexed by PodUID to ContainerName 58 podTopologyHints podTopologyHints 59 // The list of components registered with the Manager 60 hintProviders []HintProvider 61 // Topology Manager Policy 62 policy Policy 63 // Mapping of (PodUid, ContainerName) to ContainerID for Adding/Removing Pods from PodTopologyHints mapping 64 podMap containermap.ContainerMap 65} 66 67func (s *scope) Name() string { 68 return s.name 69} 70 71func (s *scope) getTopologyHints(podUID string, containerName string) TopologyHint { 72 s.mutex.Lock() 73 defer s.mutex.Unlock() 74 return s.podTopologyHints[podUID][containerName] 75} 76 77func (s *scope) setTopologyHints(podUID string, containerName string, th TopologyHint) { 78 s.mutex.Lock() 79 defer s.mutex.Unlock() 80 81 if s.podTopologyHints[podUID] == nil { 82 s.podTopologyHints[podUID] = make(map[string]TopologyHint) 83 } 84 s.podTopologyHints[podUID][containerName] = th 85} 86 87func (s *scope) GetAffinity(podUID string, containerName string) TopologyHint { 88 return s.getTopologyHints(podUID, containerName) 89} 90 91func (s *scope) AddHintProvider(h HintProvider) { 92 s.hintProviders = append(s.hintProviders, h) 93} 94 95// It would be better to implement this function in topologymanager instead of scope 96// but topologymanager do not track mapping anymore 97func (s *scope) AddContainer(pod *v1.Pod, container *v1.Container, containerID string) { 98 s.mutex.Lock() 99 defer s.mutex.Unlock() 100 101 s.podMap.Add(string(pod.UID), container.Name, containerID) 102} 103 104// It would be better to implement this function in topologymanager instead of scope 105// but topologymanager do not track mapping anymore 106func (s *scope) RemoveContainer(containerID string) error { 107 s.mutex.Lock() 108 defer s.mutex.Unlock() 109 110 klog.InfoS("RemoveContainer", "containerID", containerID) 111 // Get the podUID and containerName associated with the containerID to be removed and remove it 112 podUIDString, containerName, err := s.podMap.GetContainerRef(containerID) 113 if err != nil { 114 return nil 115 } 116 s.podMap.RemoveByContainerID(containerID) 117 118 // In cases where a container has been restarted, it's possible that the same podUID and 119 // containerName are already associated with a *different* containerID now. Only remove 120 // the TopologyHints associated with that podUID and containerName if this is not true 121 if _, err := s.podMap.GetContainerID(podUIDString, containerName); err != nil { 122 delete(s.podTopologyHints[podUIDString], containerName) 123 if len(s.podTopologyHints[podUIDString]) == 0 { 124 delete(s.podTopologyHints, podUIDString) 125 } 126 } 127 128 return nil 129} 130 131func (s *scope) admitPolicyNone(pod *v1.Pod) lifecycle.PodAdmitResult { 132 for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) { 133 err := s.allocateAlignedResources(pod, &container) 134 if err != nil { 135 return admission.GetPodAdmitResult(err) 136 } 137 } 138 return admission.GetPodAdmitResult(nil) 139} 140 141// It would be better to implement this function in topologymanager instead of scope 142// but topologymanager do not track providers anymore 143func (s *scope) allocateAlignedResources(pod *v1.Pod, container *v1.Container) error { 144 for _, provider := range s.hintProviders { 145 err := provider.Allocate(pod, container) 146 if err != nil { 147 return err 148 } 149 } 150 return nil 151} 152