github.com/kubewharf/katalyst-core@v0.5.3/pkg/metaserver/agent/pod/runtime.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 pod
    18  
    19  import (
    20  	"fmt"
    21  	"time"
    22  
    23  	kubetypes "k8s.io/apimachinery/pkg/types"
    24  	cri "k8s.io/cri-api/pkg/apis"
    25  	runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
    26  	"k8s.io/klog/v2"
    27  	"k8s.io/kubernetes/pkg/kubelet/cri/remote"
    28  	"k8s.io/kubernetes/pkg/kubelet/types"
    29  
    30  	"github.com/kubewharf/katalyst-core/pkg/config/agent/global"
    31  	"github.com/kubewharf/katalyst-core/pkg/util/general"
    32  )
    33  
    34  // RuntimePod is a group of containers.
    35  type RuntimePod struct {
    36  	// The UID of the pod, which can be used to retrieve a particular pod
    37  	// from the pod list returned by GetPods().
    38  	UID kubetypes.UID
    39  	// The name and namespace of the pod, which is readable by human.
    40  	Name      string
    41  	Namespace string
    42  	// List of containers that belongs to this pod. It may contain only
    43  	// running containers, or mixed with dead ones (when GetPods(true)).
    44  	Containers []*runtimeapi.Container
    45  	// List of sandboxes associated with this pod. This is only populated
    46  	// by kuberuntime.
    47  	Sandboxes []*runtimeapi.PodSandbox
    48  }
    49  
    50  type labeledContainerInfo struct {
    51  	ContainerName string
    52  	PodName       string
    53  	PodNamespace  string
    54  	runtimeName   string
    55  	PodUID        kubetypes.UID
    56  }
    57  
    58  type RuntimePodFetcher interface {
    59  	GetPods(all bool) ([]*RuntimePod, error)
    60  }
    61  
    62  type runtimePodFetcherImpl struct {
    63  	runtimeService cri.RuntimeService
    64  }
    65  
    66  func NewRuntimePodFetcher(baseConf *global.BaseConfiguration) (RuntimePodFetcher, error) {
    67  	runtimeService, err := remote.NewRemoteRuntimeService(baseConf.RuntimeEndpoint, 2*time.Minute)
    68  	if err != nil {
    69  		return nil, fmt.Errorf("create remote runtime service failed %s", err)
    70  	}
    71  
    72  	return &runtimePodFetcherImpl{runtimeService: runtimeService}, nil
    73  }
    74  
    75  // GetPods returns a list of containers grouped by pods. The boolean parameter
    76  // specifies whether the runtime returns all containers including those already
    77  // exited and dead containers (used for garbage collection).
    78  func (r *runtimePodFetcherImpl) GetPods(all bool) ([]*RuntimePod, error) {
    79  	pods := make(map[kubetypes.UID]*RuntimePod)
    80  	sandboxes, err := r.getKubeletSandboxes(all)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	for i := range sandboxes {
    85  		s := sandboxes[i]
    86  		if s.Metadata == nil {
    87  			klog.V(4).InfoS("Sandbox does not have metadata", "sandbox", s)
    88  			continue
    89  		}
    90  		podUID := kubetypes.UID(s.Metadata.Uid)
    91  		if _, ok := pods[podUID]; !ok {
    92  			pods[podUID] = &RuntimePod{
    93  				UID:       podUID,
    94  				Name:      s.Metadata.Name,
    95  				Namespace: s.Metadata.Namespace,
    96  			}
    97  		}
    98  		p := pods[podUID]
    99  		p.Sandboxes = append(p.Sandboxes, s)
   100  	}
   101  
   102  	containers, err := r.getKubeletContainers(all)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	for i := range containers {
   107  		c := containers[i]
   108  		if c.Metadata == nil {
   109  			klog.V(4).InfoS("Container does not have metadata", "container", c)
   110  			continue
   111  		}
   112  
   113  		labelledInfo := getContainerInfoFromLabels(c.Labels)
   114  		pod, found := pods[labelledInfo.PodUID]
   115  		if !found {
   116  			pod = &RuntimePod{
   117  				UID:       labelledInfo.PodUID,
   118  				Name:      labelledInfo.PodName,
   119  				Namespace: labelledInfo.PodNamespace,
   120  			}
   121  			pods[labelledInfo.PodUID] = pod
   122  		}
   123  		pod.Containers = append(pod.Containers, c)
   124  	}
   125  
   126  	// Convert map to list.
   127  	var result []*RuntimePod
   128  	for _, pod := range pods {
   129  		result = append(result, pod)
   130  	}
   131  
   132  	return result, nil
   133  }
   134  
   135  // getKubeletSandboxes lists all (or just the running) sandboxes managed by kubelet.
   136  func (r *runtimePodFetcherImpl) getKubeletSandboxes(all bool) ([]*runtimeapi.PodSandbox, error) {
   137  	var filter *runtimeapi.PodSandboxFilter
   138  	if !all {
   139  		readyState := runtimeapi.PodSandboxState_SANDBOX_READY
   140  		filter = &runtimeapi.PodSandboxFilter{
   141  			State: &runtimeapi.PodSandboxStateValue{
   142  				State: readyState,
   143  			},
   144  		}
   145  	}
   146  
   147  	resp, err := r.runtimeService.ListPodSandbox(filter)
   148  	if err != nil {
   149  		klog.ErrorS(err, "Failed to list pod sandboxes")
   150  		return nil, err
   151  	}
   152  
   153  	return resp, nil
   154  }
   155  
   156  // getKubeletContainers lists containers managed by kubelet.
   157  // The boolean parameter specifies whether returns all containers including
   158  // those already exited and dead containers (used for garbage collection).
   159  func (r *runtimePodFetcherImpl) getKubeletContainers(allContainers bool) ([]*runtimeapi.Container, error) {
   160  	filter := &runtimeapi.ContainerFilter{}
   161  	if !allContainers {
   162  		filter.State = &runtimeapi.ContainerStateValue{
   163  			State: runtimeapi.ContainerState_CONTAINER_RUNNING,
   164  		}
   165  	}
   166  
   167  	containers, err := r.runtimeService.ListContainers(filter)
   168  	if err != nil {
   169  		klog.ErrorS(err, "ListContainers failed")
   170  		return nil, err
   171  	}
   172  
   173  	return containers, nil
   174  }
   175  
   176  // getContainerInfoFromLabels gets labeledContainerInfo from labels.
   177  func getContainerInfoFromLabels(labels map[string]string) *labeledContainerInfo {
   178  	return &labeledContainerInfo{
   179  		PodName:       general.GetStringValueFromMap(labels, types.KubernetesPodNameLabel),
   180  		PodNamespace:  general.GetStringValueFromMap(labels, types.KubernetesPodNamespaceLabel),
   181  		PodUID:        kubetypes.UID(general.GetStringValueFromMap(labels, types.KubernetesPodUIDLabel)),
   182  		ContainerName: general.GetStringValueFromMap(labels, types.KubernetesContainerNameLabel),
   183  	}
   184  }