github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/pkg/model/k8s_target.go (about) 1 package model 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/tilt-dev/tilt/internal/sliceutils" 8 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 9 ) 10 11 // Specifies how a Pod's state factors into determining whether a resource is ready 12 type PodReadinessMode string 13 14 // Pod readiness isn't applicable to this resource 15 const PodReadinessNone PodReadinessMode = "" 16 17 // Always wait for pods to become ready. 18 const PodReadinessWait PodReadinessMode = "wait" 19 20 // Don't even wait for pods to appear. 21 const PodReadinessIgnore PodReadinessMode = "ignore" 22 23 // wait until the pod has completed successfully 24 const PodReadinessSucceeded PodReadinessMode = "succeeded" 25 26 type K8sTarget struct { 27 // An apiserver-driven data model for applying Kubernetes YAML. 28 // 29 // This will eventually replace K8sTarget. We represent this as an embedded 30 // struct while we're migrating fields. 31 v1alpha1.KubernetesApplySpec 32 33 Name TargetName 34 35 PodReadinessMode PodReadinessMode 36 37 // Map configRef -> number of times we (expect to) inject it. 38 // NOTE(maia): currently this map is only for use in metrics, though someday 39 // we want a better way of mapping configRefs -> their injection point(s) 40 // (right now, Tiltfile and Engine have two different ways of finding a 41 // given image in a k8s entity. 42 refInjectCounts map[string]int 43 44 // zero+ links assoc'd with this resource (to be displayed in UIs, 45 // in addition to any port forwards/LB endpoints) 46 Links []Link 47 48 // pathDependencies are files required by this target. 49 // 50 // For Tiltfile-based, YAML-driven (i.e. `k8s_yaml()`) resources, this is 51 // NOT used because it's not sufficient to reload the YAML and re-deploy; 52 // there is a lot of post-Tiltfile-load logic for resource assembly, image 53 // locator injection, etc. As a result, these resources have their YAML 54 // files registered as "config files", which cause the Tiltfile to be 55 // re-evaluated. 56 pathDependencies []string 57 58 FileWatchIgnores []v1alpha1.IgnoreDef 59 } 60 61 func NewK8sTargetForTesting(yaml string) K8sTarget { 62 apply := v1alpha1.KubernetesApplySpec{ 63 YAML: yaml, 64 } 65 return K8sTarget{KubernetesApplySpec: apply} 66 } 67 68 func (k8s K8sTarget) GetFileWatchIgnores() []v1alpha1.IgnoreDef { 69 return k8s.FileWatchIgnores 70 } 71 72 func (k8s K8sTarget) Empty() bool { return reflect.DeepEqual(k8s, K8sTarget{}) } 73 74 func (k8s K8sTarget) DependencyIDs() []TargetID { 75 result := make([]TargetID, 0, len(k8s.ImageMaps)) 76 for _, im := range k8s.ImageMaps { 77 result = append(result, TargetID{ 78 Type: TargetTypeImage, 79 Name: TargetName(im), 80 }) 81 } 82 return result 83 } 84 85 func (k8s K8sTarget) RefInjectCounts() map[string]int { 86 return k8s.refInjectCounts 87 } 88 89 func (k8s K8sTarget) Validate() error { 90 if k8s.ID().Empty() { 91 return fmt.Errorf("[Validate] K8s resources missing name:\n%s", k8s.YAML) 92 } 93 94 // TODO(milas): improve error message 95 if k8s.KubernetesApplySpec.YAML == "" && k8s.KubernetesApplySpec.ApplyCmd == nil { 96 return fmt.Errorf("[Validate] K8s resources %q missing YAML", k8s.Name) 97 } 98 99 return nil 100 } 101 102 func (k8s K8sTarget) ID() TargetID { 103 return TargetID{ 104 Type: TargetTypeK8s, 105 Name: k8s.Name, 106 } 107 } 108 109 // Dependencies are files required by this target. 110 // 111 // Part of the WatchableTarget interface. 112 func (k8s K8sTarget) Dependencies() []string { 113 // sorting/de-duping guaranteed by setter 114 return k8s.pathDependencies 115 } 116 117 // Track which images this depends on. 118 func (k8s K8sTarget) WithImageDependencies(imageMapDeps []string) K8sTarget { 119 k8s.ImageMaps = sliceutils.Dedupe(imageMapDeps) 120 return k8s 121 } 122 123 // WithPathDependencies registers paths that this K8sTarget depends on. 124 func (k8s K8sTarget) WithPathDependencies(paths []string) K8sTarget { 125 k8s.pathDependencies = sliceutils.DedupedAndSorted(paths) 126 return k8s 127 } 128 129 func (k8s K8sTarget) WithRefInjectCounts(ric map[string]int) K8sTarget { 130 k8s.refInjectCounts = ric 131 return k8s 132 } 133 134 func (k8s K8sTarget) WithIgnores(ignores []v1alpha1.IgnoreDef) K8sTarget { 135 k8s.FileWatchIgnores = ignores 136 return k8s 137 } 138 139 var _ TargetSpec = K8sTarget{} 140 141 func FilterLiveUpdateOnly(imageMapDeps []string, imageTargets []ImageTarget) []string { 142 result := make([]string, 0, len(imageMapDeps)) 143 isLiveUpdateOnly := make(map[string]bool, len(imageTargets)) 144 for _, image := range imageTargets { 145 isLiveUpdateOnly[image.ImageMapName()] = image.IsLiveUpdateOnly 146 } 147 for _, im := range imageMapDeps { 148 if isLiveUpdateOnly[im] { 149 continue 150 } 151 result = append(result, im) 152 } 153 return result 154 }