github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/controllers/apis/configmap/disable.go (about) 1 package configmap 2 3 import ( 4 "context" 5 "fmt" 6 "strconv" 7 8 apierrors "k8s.io/apimachinery/pkg/api/errors" 9 "k8s.io/apimachinery/pkg/types" 10 "sigs.k8s.io/controller-runtime/pkg/client" 11 12 "github.com/tilt-dev/tilt/pkg/apis" 13 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 14 ) 15 16 type DisableResult int 17 18 func DisableStatus(getCM func(name string) (v1alpha1.ConfigMap, error), disableSource *v1alpha1.DisableSource) (result v1alpha1.DisableState, reason string, err error) { 19 if disableSource == nil { 20 // if there is no source, assume the object has opted out of being disabled and is always eanbled 21 return v1alpha1.DisableStateEnabled, "object does not specify a DisableSource", nil 22 } 23 24 if disableSource.ConfigMap != nil { 25 return cmDisableState(getCM, *disableSource.ConfigMap) 26 } 27 28 if len(disableSource.EveryConfigMap) > 0 { 29 for _, cm := range disableSource.EveryConfigMap { 30 state, reason, err := cmDisableState(getCM, cm) 31 if state != v1alpha1.DisableStateDisabled { 32 return state, reason, err 33 } 34 } 35 return v1alpha1.DisableStateDisabled, "Every ConfigMap disabled", nil 36 } 37 38 return v1alpha1.DisableStateError, "DisableSource specifies no valid sources", nil 39 } 40 41 func cmDisableState(getCM func(name string) (v1alpha1.ConfigMap, error), source v1alpha1.ConfigMapDisableSource) (v1alpha1.DisableState, string, error) { 42 name := source.Name 43 key := source.Key 44 cm, err := getCM(name) 45 if err != nil { 46 if apierrors.IsNotFound(err) { 47 return v1alpha1.DisableStatePending, fmt.Sprintf("ConfigMap %q does not exist", name), nil 48 } 49 return v1alpha1.DisableStatePending, fmt.Sprintf("error reading ConfigMap %q", name), err 50 } 51 52 cmVal, ok := cm.Data[key] 53 if !ok { 54 return v1alpha1.DisableStateError, fmt.Sprintf("ConfigMap %q has no key %q", name, key), nil 55 } 56 57 isDisabled, err := strconv.ParseBool(cmVal) 58 if err != nil { 59 return v1alpha1.DisableStateError, fmt.Sprintf("error parsing ConfigMap/key %q/%q value %q as a bool: %v", name, key, cmVal, err.Error()), nil 60 } 61 62 var result v1alpha1.DisableState 63 if isDisabled { 64 result = v1alpha1.DisableStateDisabled 65 } else { 66 result = v1alpha1.DisableStateEnabled 67 } 68 return result, fmt.Sprintf("ConfigMap/key %q/%q is %v", name, key, isDisabled), nil 69 } 70 71 // Returns a new DisableStatus if the disable status has changed, or the prev status if it hasn't. 72 func MaybeNewDisableStatus(ctx context.Context, client client.Client, disableSource *v1alpha1.DisableSource, prevStatus *v1alpha1.DisableStatus) (*v1alpha1.DisableStatus, error) { 73 getCM := func(name string) (v1alpha1.ConfigMap, error) { 74 var cm v1alpha1.ConfigMap 75 err := client.Get(ctx, types.NamespacedName{Name: name}, &cm) 76 return cm, err 77 } 78 79 result, reason, err := DisableStatus(getCM, disableSource) 80 if err != nil { 81 return nil, err 82 } 83 // we treat pending as disabled 84 // eventually we should probably represent isDisabled by an enum in the API, but for now 85 // we treat pending as disabled, with the understanding that it's better to momentarily delay the start of an 86 // object than to spin it up and quickly kill it, as the latter might generate undesired side effects / logs 87 isDisabled := result == v1alpha1.DisableStateDisabled || result == v1alpha1.DisableStatePending || result == v1alpha1.DisableStateError 88 statusDiffers := prevStatus == nil || prevStatus.State != result || prevStatus.Reason != reason 89 if statusDiffers { 90 return &v1alpha1.DisableStatus{ 91 Disabled: isDisabled, 92 LastUpdateTime: apis.Now(), 93 Reason: reason, 94 State: result, 95 }, nil 96 } 97 return prevStatus, nil 98 }