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  }