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 }