github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/store/liveupdates/containers.go (about)

     1  package liveupdates
     2  
     3  import (
     4  	"fmt"
     5  
     6  	v1 "k8s.io/api/core/v1"
     7  
     8  	"github.com/tilt-dev/tilt/internal/container"
     9  	"github.com/tilt-dev/tilt/internal/controllers/apis/liveupdate"
    10  	"github.com/tilt-dev/tilt/internal/k8s"
    11  	"github.com/tilt-dev/tilt/internal/store/k8sconv"
    12  	"github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1"
    13  )
    14  
    15  // If all containers running the given image are ready, returns info for them.
    16  // (If this image is running on multiple pods, return an error.)
    17  func RunningContainersForOnePod(
    18  	selector *v1alpha1.LiveUpdateKubernetesSelector,
    19  	resource *k8sconv.KubernetesResource,
    20  	imageMap *v1alpha1.ImageMap,
    21  ) ([]Container, error) {
    22  	if selector == nil || resource == nil {
    23  		return nil, nil
    24  	}
    25  
    26  	activePods := []v1alpha1.Pod{}
    27  	for _, p := range resource.FilteredPods {
    28  		// Ignore completed pods.
    29  		if p.Phase == string(v1.PodSucceeded) || p.Phase == string(v1.PodFailed) {
    30  			continue
    31  		}
    32  		activePods = append(activePods, p)
    33  	}
    34  
    35  	if len(activePods) == 0 {
    36  		return nil, nil
    37  	}
    38  	if len(activePods) > 1 {
    39  		return nil, fmt.Errorf("can only get container info for a single pod; image target %s has %d pods", selector.Image, len(resource.FilteredPods))
    40  	}
    41  
    42  	pod := activePods[0]
    43  	var containers []Container
    44  	for _, c := range pod.Containers {
    45  		if !liveupdate.KubernetesSelectorMatchesContainer(c, selector, imageMap) {
    46  			continue
    47  		}
    48  		if c.ID == "" || c.Name == "" || c.State.Running == nil {
    49  			// If we're missing any relevant info for this container, OR if the
    50  			// container isn't running, we can't update it in place.
    51  			// (Since we'll need to fully rebuild this image, we shouldn't bother
    52  			// in-place updating ANY containers on this pod -- they'll all
    53  			// be recreated when we image build. So don't return ANY Containers.)
    54  			return nil, nil
    55  		}
    56  		containers = append(containers, Container{
    57  			PodID:         k8s.PodID(pod.Name),
    58  			ContainerID:   container.ID(c.ID),
    59  			ContainerName: container.Name(c.Name),
    60  			Namespace:     k8s.Namespace(pod.Namespace),
    61  		})
    62  	}
    63  
    64  	return containers, nil
    65  }
    66  
    67  func RunningContainersForDC(dcs *v1alpha1.DockerComposeService) []Container {
    68  	if dcs == nil || dcs.Status.ContainerID == "" {
    69  		return nil
    70  	}
    71  	return []Container{
    72  		Container{ContainerID: container.ID(dcs.Status.ContainerID)},
    73  	}
    74  }
    75  
    76  // Information describing a single running & ready container
    77  type Container struct {
    78  	PodID         k8s.PodID
    79  	ContainerID   container.ID
    80  	ContainerName container.Name
    81  	Namespace     k8s.Namespace
    82  }
    83  
    84  func (c Container) Empty() bool {
    85  	return c == Container{}
    86  }
    87  
    88  func (c Container) DisplayName() string {
    89  	if c.PodID == "" {
    90  		if c.ContainerName == "" {
    91  			return c.ContainerID.ShortStr()
    92  		}
    93  		return c.ContainerName.String()
    94  	}
    95  
    96  	return fmt.Sprintf("%s/%s", c.PodID, c.ContainerName)
    97  }