github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/orm/pod_resource.go (about) 1 /* 2 Copyright 2022 The Katalyst Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package orm 18 19 import ( 20 "encoding/json" 21 "reflect" 22 "sync" 23 24 //nolint 25 "github.com/golang/protobuf/proto" 26 "k8s.io/apimachinery/pkg/util/sets" 27 "k8s.io/klog/v2" 28 pluginapi "k8s.io/kubelet/pkg/apis/resourceplugin/v1alpha1" 29 30 "github.com/kubewharf/katalyst-core/pkg/agent/orm/checkpoint" 31 ) 32 33 type ( 34 ResourceAllocation map[string]*pluginapi.ResourceAllocationInfo // Keyed by resourceName. 35 ContainerResources map[string]ResourceAllocation // Keyed by containerName. 36 PodResources map[string]ContainerResources // Keyed by podUID 37 ) 38 39 type podResourcesChk struct { 40 sync.RWMutex 41 resources PodResources // Keyed by podUID. 42 } 43 44 var EmptyValue = reflect.Value{} 45 46 func newPodResourcesChk() *podResourcesChk { 47 return &podResourcesChk{ 48 resources: make(PodResources), 49 } 50 } 51 52 func (pr PodResources) DeepCopy() PodResources { 53 copiedPodResources := make(PodResources) 54 55 for podUID, containerResources := range pr { 56 copiedPodResources[podUID] = containerResources.DeepCopy() 57 } 58 59 return copiedPodResources 60 } 61 62 func (cr ContainerResources) DeepCopy() ContainerResources { 63 copiedContainerResources := make(ContainerResources) 64 65 for containerName, resouceAllocation := range cr { 66 copiedContainerResources[containerName] = resouceAllocation.DeepCopy() 67 } 68 69 return copiedContainerResources 70 } 71 72 func (ra ResourceAllocation) DeepCopy() ResourceAllocation { 73 copiedResourceAllocation := make(ResourceAllocation) 74 75 for resourceName, allocationInfo := range ra { 76 copiedResourceAllocation[resourceName] = proto.Clone(allocationInfo).(*pluginapi.ResourceAllocationInfo) 77 } 78 79 return copiedResourceAllocation 80 } 81 82 func (pres *podResourcesChk) pods() sets.String { 83 pres.RLock() 84 defer pres.RUnlock() 85 86 ret := sets.NewString() 87 for k := range pres.resources { 88 ret.Insert(k) 89 } 90 return ret 91 } 92 93 // "resourceName" here is different than "resourceName" in qrm allocation, one qrm plugin may 94 // only represent one resource in allocation, but can also return several other resourceNames 95 // to store in pod resources 96 func (pres *podResourcesChk) insert(podUID, contName, resourceName string, allocationInfo *pluginapi.ResourceAllocationInfo) { 97 if allocationInfo == nil { 98 return 99 } 100 101 pres.Lock() 102 defer pres.Unlock() 103 104 if _, podExists := pres.resources[podUID]; !podExists { 105 pres.resources[podUID] = make(ContainerResources) 106 } 107 if _, contExists := pres.resources[podUID][contName]; !contExists { 108 pres.resources[podUID][contName] = make(ResourceAllocation) 109 } 110 111 pres.resources[podUID][contName][resourceName] = proto.Clone(allocationInfo).(*pluginapi.ResourceAllocationInfo) 112 } 113 114 func (pres *podResourcesChk) deleteResourceAllocationInfo(podUID, contName, resourceName string) { 115 pres.Lock() 116 defer pres.Unlock() 117 118 if pres.resources[podUID] != nil && pres.resources[podUID][contName] != nil { 119 delete(pres.resources[podUID][contName], resourceName) 120 } 121 } 122 123 func (pres *podResourcesChk) deletePod(podUID string) { 124 pres.Lock() 125 defer pres.Unlock() 126 127 if pres.resources == nil { 128 return 129 } 130 131 delete(pres.resources, podUID) 132 } 133 134 func (pres *podResourcesChk) delete(pods []string) { 135 pres.Lock() 136 defer pres.Unlock() 137 138 if pres.resources == nil { 139 return 140 } 141 142 for _, uid := range pods { 143 delete(pres.resources, uid) 144 } 145 } 146 147 func (pres *podResourcesChk) podResources(podUID string) ContainerResources { 148 pres.RLock() 149 defer pres.RUnlock() 150 151 if _, podExists := pres.resources[podUID]; !podExists { 152 return nil 153 } 154 155 return pres.resources[podUID] 156 } 157 158 // Returns all resources information allocated to the given container. 159 // Returns nil if we don't have cached state for the given <podUID, contName>. 160 func (pres *podResourcesChk) containerAllResources(podUID, contName string) ResourceAllocation { 161 pres.RLock() 162 defer pres.RUnlock() 163 164 if _, podExists := pres.resources[podUID]; !podExists { 165 return nil 166 } 167 if _, contExists := pres.resources[podUID][contName]; !contExists { 168 return nil 169 } 170 171 return pres.resources[podUID][contName].DeepCopy() 172 } 173 174 func (pres *podResourcesChk) containerResource(podUID, contName, resource string) *pluginapi.ResourceAllocationInfo { 175 pres.RLock() 176 defer pres.RUnlock() 177 178 if _, podExists := pres.resources[podUID]; !podExists { 179 return nil 180 } 181 if _, contExists := pres.resources[podUID][contName]; !contExists { 182 return nil 183 } 184 resourceAllocationInfo, resourceExists := pres.resources[podUID][contName][resource] 185 if !resourceExists || resourceAllocationInfo == nil { 186 return nil 187 } 188 return proto.Clone(resourceAllocationInfo).(*pluginapi.ResourceAllocationInfo) 189 } 190 191 // Turns podResourcesChk to checkpointData. 192 func (pres *podResourcesChk) toCheckpointData() []checkpoint.PodResourcesEntry { 193 pres.RLock() 194 defer pres.RUnlock() 195 196 var data []checkpoint.PodResourcesEntry 197 for podUID, containerResources := range pres.resources { 198 for conName, resourcesAllocation := range containerResources { 199 for resourceName, allocationInfo := range resourcesAllocation { 200 allocRespBytes, err := json.Marshal(allocationInfo) 201 if err != nil { 202 klog.Errorf("Can't marshal allocationInfo for %v %v %v: %v", podUID, conName, resourceName, err) 203 continue 204 } 205 data = append(data, checkpoint.PodResourcesEntry{ 206 PodUID: podUID, 207 ContainerName: conName, 208 ResourceName: resourceName, 209 AllocationInfo: string(allocRespBytes), 210 }) 211 } 212 } 213 } 214 return data 215 } 216 217 // Populates podResourcesChk from the passed in checkpointData. 218 func (pres *podResourcesChk) fromCheckpointData(data []checkpoint.PodResourcesEntry) { 219 for _, entry := range data { 220 klog.V(2).Infof("Get checkpoint entry: %s %s %s %s\n", 221 entry.PodUID, entry.ContainerName, entry.ResourceName, entry.AllocationInfo) 222 allocationInfo := &pluginapi.ResourceAllocationInfo{} 223 err := json.Unmarshal([]byte(entry.AllocationInfo), allocationInfo) 224 if err != nil { 225 klog.Errorf("Can't unmarshal allocationInfo for %s %s %s %s: %v", 226 entry.PodUID, entry.ContainerName, entry.ResourceName, entry.AllocationInfo, err) 227 continue 228 } 229 pres.insert(entry.PodUID, entry.ContainerName, entry.ResourceName, allocationInfo) 230 } 231 } 232 233 func (pres *podResourcesChk) allAllocatedResourceNames() sets.String { 234 pres.RLock() 235 defer pres.RUnlock() 236 237 res := sets.NewString() 238 239 for _, containerResources := range pres.resources { 240 for _, resourcesAllocation := range containerResources { 241 for resourceName := range resourcesAllocation { 242 res.Insert(resourceName) 243 } 244 } 245 } 246 247 return res 248 }