github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/controllers/core/kubernetesdiscovery/container_restart.go (about)

     1  package kubernetesdiscovery
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"k8s.io/apimachinery/pkg/types"
     7  
     8  	"github.com/tilt-dev/tilt/internal/container"
     9  	"github.com/tilt-dev/tilt/internal/k8s"
    10  	"github.com/tilt-dev/tilt/internal/store"
    11  	"github.com/tilt-dev/tilt/internal/store/k8sconv"
    12  	"github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1"
    13  	"github.com/tilt-dev/tilt/pkg/logger"
    14  	"github.com/tilt-dev/tilt/pkg/model"
    15  )
    16  
    17  type ContainerRestartDetector struct{}
    18  
    19  func NewContainerRestartDetector() *ContainerRestartDetector {
    20  	return &ContainerRestartDetector{}
    21  }
    22  
    23  func (c *ContainerRestartDetector) Detect(dispatcher Dispatcher, prevStatus v1alpha1.KubernetesDiscoveryStatus, current *v1alpha1.KubernetesDiscovery) {
    24  	mn := model.ManifestName(current.Annotations[v1alpha1.AnnotationManifest])
    25  	if mn == "" {
    26  		// log actions are dispatched by manifest, so if this spec isn't associated with a manifest,
    27  		// there's no reason to proceed
    28  		return
    29  	}
    30  	prevPods := podsByUID(prevStatus)
    31  	currentPods := podsByUID(current.Status)
    32  	for uid, currentPod := range currentPods {
    33  		c.handlePod(dispatcher, mn, prevPods[uid], currentPod)
    34  	}
    35  }
    36  
    37  func (c *ContainerRestartDetector) handlePod(dispatcher Dispatcher, mn model.ManifestName, prev *v1alpha1.Pod, current *v1alpha1.Pod) {
    38  	if prev == nil {
    39  		// this is a new pod, so there's nothing to diff off for restarts
    40  		return
    41  	}
    42  	c.logRestarts(dispatcher, mn, current, restartedNames(prev.InitContainers, current.InitContainers))
    43  	c.logRestarts(dispatcher, mn, current, restartedNames(prev.Containers, current.Containers))
    44  }
    45  
    46  func (c *ContainerRestartDetector) logRestarts(dispatcher Dispatcher, mn model.ManifestName, pod *v1alpha1.Pod, restarted []container.Name) {
    47  	spanID := k8sconv.SpanIDForPod(mn, k8s.PodID(pod.Name))
    48  	for _, containerName := range restarted {
    49  		msg := fmt.Sprintf("Detected container restart. Pod: %s. Container: %s.", pod.Name, containerName)
    50  		dispatcher.Dispatch(store.NewLogAction(mn, spanID, logger.WarnLvl, nil, []byte(msg)))
    51  	}
    52  }
    53  
    54  func podsByUID(status v1alpha1.KubernetesDiscoveryStatus) map[types.UID]*v1alpha1.Pod {
    55  	pods := make(map[types.UID]*v1alpha1.Pod)
    56  	for i := range status.Pods {
    57  		pods[types.UID(status.Pods[i].UID)] = status.Pods[i].DeepCopy()
    58  	}
    59  	return pods
    60  }
    61  
    62  func restartedNames(prev []v1alpha1.Container, current []v1alpha1.Container) []container.Name {
    63  	var result []container.Name
    64  	for i, c := range current {
    65  		if i >= len(prev) {
    66  			break
    67  		}
    68  
    69  		existing := prev[i]
    70  		if existing.Name != c.Name {
    71  			continue
    72  		}
    73  
    74  		if c.Restarts > existing.Restarts {
    75  			result = append(result, container.Name(c.Name))
    76  		}
    77  	}
    78  	return result
    79  }