github.com/grahambrereton-form3/tilt@v0.10.18/internal/store/runtime_state.go (about)

     1  package store
     2  
     3  import (
     4  	"net/url"
     5  	"time"
     6  
     7  	"github.com/docker/distribution/reference"
     8  	v1 "k8s.io/api/core/v1"
     9  	"k8s.io/apimachinery/pkg/types"
    10  
    11  	"github.com/windmilleng/tilt/internal/container"
    12  	"github.com/windmilleng/tilt/internal/k8s"
    13  	"github.com/windmilleng/tilt/pkg/model"
    14  )
    15  
    16  type RuntimeState interface {
    17  	RuntimeState()
    18  	HasEverBeenReady() bool
    19  }
    20  
    21  // Currently just a placeholder, as a LocalResource has no runtime state, only "build"
    22  // state. In future, we may use this to store runtime state for long-running processes
    23  // kicked off via a LocalResource.
    24  type LocalRuntimeState struct {
    25  	HasSucceededAtLeastOnce bool
    26  }
    27  
    28  func (LocalRuntimeState) RuntimeState() {}
    29  
    30  func (l LocalRuntimeState) HasEverBeenReady() bool {
    31  	return l.HasSucceededAtLeastOnce
    32  }
    33  
    34  var _ RuntimeState = LocalRuntimeState{}
    35  
    36  type K8sRuntimeState struct {
    37  	// The ancestor that we match pods against to associate them with this manifest.
    38  	// If we deployed Pod YAML, this will be the Pod UID.
    39  	// In many cases, this will be a Deployment UID.
    40  	PodAncestorUID types.UID
    41  
    42  	Pods           map[k8s.PodID]*Pod
    43  	LBs            map[k8s.ServiceName]*url.URL
    44  	DeployedUIDSet UIDSet
    45  
    46  	LastReadyTime time.Time
    47  }
    48  
    49  func (K8sRuntimeState) RuntimeState() {}
    50  
    51  var _ RuntimeState = K8sRuntimeState{}
    52  
    53  func NewK8sRuntimeState(pods ...Pod) K8sRuntimeState {
    54  	podMap := make(map[k8s.PodID]*Pod, len(pods))
    55  	for _, pod := range pods {
    56  		p := pod
    57  		podMap[p.PodID] = &p
    58  	}
    59  	return K8sRuntimeState{
    60  		Pods:           podMap,
    61  		LBs:            make(map[k8s.ServiceName]*url.URL),
    62  		DeployedUIDSet: NewUIDSet(),
    63  	}
    64  }
    65  
    66  func (s K8sRuntimeState) HasEverBeenReady() bool {
    67  	return !s.LastReadyTime.IsZero()
    68  }
    69  
    70  func (s K8sRuntimeState) PodLen() int {
    71  	return len(s.Pods)
    72  }
    73  
    74  func (s K8sRuntimeState) ContainsID(id k8s.PodID) bool {
    75  	_, ok := s.Pods[id]
    76  	return ok
    77  }
    78  
    79  func (s K8sRuntimeState) PodList() []Pod {
    80  	pods := make([]Pod, 0, len(s.Pods))
    81  	for _, pod := range s.Pods {
    82  		pods = append(pods, *pod)
    83  	}
    84  	return pods
    85  }
    86  
    87  // Get the "most recent pod" from the K8sRuntimeState.
    88  // For most users, we believe there will be only one pod per manifest.
    89  // So most of this time, this will return the only pod.
    90  // And in other cases, it will return a reasonable, consistent default.
    91  func (s K8sRuntimeState) MostRecentPod() Pod {
    92  	bestPod := Pod{}
    93  	found := false
    94  
    95  	for _, v := range s.Pods {
    96  		if !found || v.isAfter(bestPod) {
    97  			bestPod = *v
    98  			found = true
    99  		}
   100  	}
   101  
   102  	return bestPod
   103  }
   104  
   105  type Pod struct {
   106  	PodID     k8s.PodID
   107  	Namespace k8s.Namespace
   108  	StartedAt time.Time
   109  	Status    string
   110  	Phase     v1.PodPhase
   111  
   112  	// Error messages from the pod state if it's in an error state.
   113  	StatusMessages []string
   114  
   115  	// Set when we get ready to replace a pod. We may do the update in-place.
   116  	UpdateStartTime time.Time
   117  
   118  	// If a pod is being deleted, Kubernetes marks it as Running
   119  	// until it actually gets removed.
   120  	Deleting bool
   121  
   122  	HasSynclet bool
   123  
   124  	// The log for the currently active pod, if any
   125  	CurrentLog model.Log `testdiff:"ignore"`
   126  
   127  	Containers []Container
   128  
   129  	// We want to show the user # of restarts since some baseline time
   130  	// i.e. Total Restarts - BaselineRestarts
   131  	BaselineRestarts int
   132  }
   133  
   134  type Container struct {
   135  	Name     container.Name
   136  	ID       container.ID
   137  	Ports    []int32
   138  	Ready    bool
   139  	ImageRef reference.Named
   140  	Restarts int
   141  }
   142  
   143  func (c Container) Empty() bool {
   144  	return c.Name == "" && c.ID == ""
   145  }
   146  
   147  func (p Pod) Empty() bool {
   148  	return p.PodID == ""
   149  }
   150  
   151  // A stable sort order for pods.
   152  func (p Pod) isAfter(p2 Pod) bool {
   153  	if p.StartedAt.After(p2.StartedAt) {
   154  		return true
   155  	} else if p2.StartedAt.After(p.StartedAt) {
   156  		return false
   157  	}
   158  	return p.PodID > p2.PodID
   159  }
   160  
   161  func (p Pod) Log() model.Log {
   162  	return p.CurrentLog
   163  }
   164  
   165  func (p Pod) AllContainerPorts() []int32 {
   166  	result := make([]int32, 0)
   167  	for _, c := range p.Containers {
   168  		result = append(result, c.Ports...)
   169  	}
   170  	return result
   171  }
   172  
   173  func (p Pod) AllContainersReady() bool {
   174  	if len(p.Containers) == 0 {
   175  		return false
   176  	}
   177  
   178  	for _, c := range p.Containers {
   179  		if !c.Ready {
   180  			return false
   181  		}
   182  	}
   183  	return true
   184  }
   185  
   186  func (p Pod) VisibleContainerRestarts() int {
   187  	return p.AllContainerRestarts() - p.BaselineRestarts
   188  }
   189  
   190  func (p Pod) AllContainerRestarts() int {
   191  	result := 0
   192  	for _, c := range p.Containers {
   193  		result += c.Restarts
   194  	}
   195  	return result
   196  }
   197  
   198  type UIDSet map[types.UID]bool
   199  
   200  func NewUIDSet() UIDSet {
   201  	return make(map[types.UID]bool)
   202  }
   203  
   204  func (s UIDSet) Add(uids ...types.UID) {
   205  	for _, uid := range uids {
   206  		s[uid] = true
   207  	}
   208  }
   209  
   210  func (s UIDSet) Contains(uid types.UID) bool {
   211  	return s[uid]
   212  }