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  }