...

Source file src/edge-infra.dev/pkg/k8s/runtime/conditions/getter.go

Documentation: edge-infra.dev/pkg/k8s/runtime/conditions

     1  package conditions
     2  
     3  import (
     4  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     5  	"sigs.k8s.io/controller-runtime/pkg/client"
     6  
     7  	"edge-infra.dev/pkg/k8s/meta/status"
     8  )
     9  
    10  // Getter interface defines methods that a Kubernetes resource object should
    11  // implement in order to use the conditions package for getting conditions.
    12  type Getter interface {
    13  	client.Object
    14  	GetConditions() []metav1.Condition
    15  }
    16  
    17  // Get returns the condition with the given type, if the condition does not
    18  // exist, it returns nil.
    19  func Get(from Getter, t string) *metav1.Condition {
    20  	conditions := from.GetConditions()
    21  	if conditions == nil {
    22  		return nil
    23  	}
    24  
    25  	for _, condition := range conditions {
    26  		if condition.Type == t {
    27  			return &condition
    28  		}
    29  	}
    30  	return nil
    31  }
    32  
    33  func GetConditions(from Getter) []metav1.Condition {
    34  	return from.GetConditions()
    35  }
    36  
    37  // Has returns true if a condition with the given type exists.
    38  func Has(from Getter, t string) bool {
    39  	return Get(from, t) != nil
    40  }
    41  
    42  // IsTrue is true if the condition with the given type is True, otherwise it is
    43  // false if the condition is not True or if the condition does not exist (is nil).
    44  func IsTrue(from Getter, t string) bool {
    45  	if c := Get(from, t); c != nil {
    46  		return c.Status == metav1.ConditionTrue
    47  	}
    48  	return false
    49  }
    50  
    51  // IsFalse is true if the condition with the given type is False, otherwise it is
    52  // false if the condition is not False or if the condition does not exist (is nil).
    53  func IsFalse(from Getter, t string) bool {
    54  	if c := Get(from, t); c != nil {
    55  		return c.Status == metav1.ConditionFalse
    56  	}
    57  	return false
    58  }
    59  
    60  // IsUnknown is true if the condition with the given type is Unknown or if the
    61  // condition does not exist (is nil).
    62  func IsUnknown(from Getter, t string) bool {
    63  	if c := Get(from, t); c != nil {
    64  		return c.Status == metav1.ConditionUnknown
    65  	}
    66  	return true
    67  }
    68  
    69  // IsReady is true if IsStalled and IsReconciling are False, and
    70  // status.ReadyCondition is True, otherwise it is false if the condition is not
    71  // True or if it does not exist (is nil).
    72  func IsReady(from Getter) bool {
    73  	return !IsStalled(from) && !IsReconciling(from) && IsTrue(from, status.ReadyCondition)
    74  }
    75  
    76  // IsStalled is true if status.StalledCondition is True and
    77  // status.ReconcilingCondition is False or does not exist, otherwise it is false.
    78  func IsStalled(from Getter) bool {
    79  	return !IsTrue(from, status.ReconcilingCondition) && IsTrue(from, status.StalledCondition)
    80  }
    81  
    82  // IsReconciling is true if status.ReconcilingCondition is True and
    83  // status.StalledCondition is False or does not exist, otherwise it is false.
    84  func IsReconciling(from Getter) bool {
    85  	return !IsTrue(from, status.StalledCondition) && IsTrue(from, status.ReconcilingCondition)
    86  }
    87  
    88  // HasAny returns true if a condition with any of the given types exist.
    89  func HasAny(from Getter, t []string) bool {
    90  	for _, ct := range t {
    91  		if Has(from, ct) {
    92  			return true
    93  		}
    94  	}
    95  	return false
    96  }
    97  
    98  // GetReason returns a nil safe string of Reason for the condition with the given
    99  // type.
   100  func GetReason(from Getter, t string) string {
   101  	if c := Get(from, t); c != nil {
   102  		return c.Reason
   103  	}
   104  	return ""
   105  }
   106  
   107  // HasReason returns true if the given condition type t exists and has Reason r
   108  func HasReason(from Getter, t, r string) bool {
   109  	if c := Get(from, t); c != nil {
   110  		return c.Reason == r
   111  	}
   112  	return false
   113  }
   114  
   115  // GetMessage returns a nil safe string of Message for the condition with the
   116  // given type.
   117  func GetMessage(from Getter, t string) string {
   118  	if c := Get(from, t); c != nil {
   119  		return c.Message
   120  	}
   121  	return ""
   122  }
   123  
   124  // GetLastTransitionTime returns the LastTransitionType or nil if the condition
   125  // does not exist (is nil).
   126  func GetLastTransitionTime(from Getter, t string) *metav1.Time {
   127  	if c := Get(from, t); c != nil {
   128  		return &c.LastTransitionTime
   129  	}
   130  	return nil
   131  }
   132  
   133  // GetObservedGeneration returns a nil safe int64 of ObservedGeneration for the
   134  // condition with the given type.
   135  func GetObservedGeneration(from Getter, t string) int64 {
   136  	if c := Get(from, t); c != nil {
   137  		return c.ObservedGeneration
   138  	}
   139  	return 0
   140  }
   141  
   142  // summary returns a condition with the summary of all the conditions existing
   143  // on an object. If the object does not have other conditions, no summary
   144  // condition is generated.
   145  func summary(from Getter, t string, options ...MergeOption) *metav1.Condition {
   146  	conditions := from.GetConditions()
   147  
   148  	mergeOpt := &mergeOptions{}
   149  	for _, o := range options {
   150  		o(mergeOpt)
   151  	}
   152  
   153  	// Identifies the conditions in scope for the Summary by taking all the
   154  	// existing conditions except t, or, if a list of conditions types is specified,
   155  	// only the conditions the condition in that list.
   156  	conditionsInScope := make([]localizedCondition, 0, len(conditions))
   157  	for i := range conditions {
   158  		c := conditions[i]
   159  		if c.Type == t {
   160  			continue
   161  		}
   162  
   163  		if mergeOpt.conditionTypes != nil {
   164  			found := false
   165  			for _, tt := range mergeOpt.conditionTypes {
   166  				if c.Type == tt {
   167  					found = true
   168  					break
   169  				}
   170  			}
   171  			if !found {
   172  				continue
   173  			}
   174  		}
   175  
   176  		conditionsInScope = append(conditionsInScope, localizedCondition{
   177  			Condition: &c,
   178  			Getter:    from,
   179  		})
   180  	}
   181  
   182  	// If it is required to add a step counter only if a subset of condition exists,
   183  	// check if the conditions in scope are included in this subset or not.
   184  	if mergeOpt.addStepCounterIfOnlyConditionTypes != nil {
   185  		for _, c := range conditionsInScope {
   186  			found := false
   187  			for _, tt := range mergeOpt.addStepCounterIfOnlyConditionTypes {
   188  				if c.Type == tt {
   189  					found = true
   190  					break
   191  				}
   192  			}
   193  			if !found {
   194  				mergeOpt.addStepCounter = false
   195  				break
   196  			}
   197  		}
   198  	}
   199  
   200  	// If it is required to add a step counter, determine the total number of
   201  	// conditions defaulting to the selected conditions or, if defined, to the
   202  	// total number of conditions type to be considered.
   203  	if mergeOpt.addStepCounter {
   204  		mergeOpt.stepCounter = len(conditionsInScope)
   205  		if mergeOpt.conditionTypes != nil {
   206  			mergeOpt.stepCounter = len(mergeOpt.conditionTypes)
   207  		}
   208  		if mergeOpt.addStepCounterIfOnlyConditionTypes != nil {
   209  			mergeOpt.stepCounter = len(mergeOpt.addStepCounterIfOnlyConditionTypes)
   210  		}
   211  	}
   212  
   213  	return merge(conditionsInScope, t, mergeOpt)
   214  }
   215  
   216  // mirrorOptions allows to set options for the mirror operation.
   217  type mirrorOptions struct {
   218  	fallbackTo      *bool
   219  	fallbackReason  string
   220  	fallbackMessage string
   221  }
   222  
   223  // MirrorOptions defines an option for mirroring conditions.
   224  type MirrorOptions func(*mirrorOptions)
   225  
   226  // WithFallbackValue specify a fallback value to use in case the mirrored
   227  // condition does not exists; in case the fallbackValue is false, given values
   228  // for reason and message will be used.
   229  func WithFallbackValue(fallbackValue bool, reason string, message string) MirrorOptions {
   230  	return func(c *mirrorOptions) {
   231  		c.fallbackTo = &fallbackValue
   232  		c.fallbackReason = reason
   233  		c.fallbackMessage = message
   234  	}
   235  }
   236  
   237  // mirror mirrors the Ready condition from a dependent object into the target
   238  // condition; if the Ready condition does not exists in the source object, no
   239  // target conditions is generated.
   240  func mirror(from Getter, targetCondition string, options ...MirrorOptions) *metav1.Condition {
   241  	mirrorOpt := &mirrorOptions{}
   242  	for _, o := range options {
   243  		o(mirrorOpt)
   244  	}
   245  
   246  	condition := Get(from, status.ReadyCondition)
   247  
   248  	if mirrorOpt.fallbackTo != nil && condition == nil {
   249  		switch *mirrorOpt.fallbackTo {
   250  		case true:
   251  			condition = TrueCondition(targetCondition, mirrorOpt.fallbackReason, "%s", mirrorOpt.fallbackMessage)
   252  		case false:
   253  			condition = FalseCondition(targetCondition, mirrorOpt.fallbackReason, "%s", mirrorOpt.fallbackMessage)
   254  		}
   255  	}
   256  
   257  	if condition != nil {
   258  		condition.Type = targetCondition
   259  	}
   260  
   261  	return condition
   262  }
   263  
   264  // aggregate the conditions from a list of depending objects into the target
   265  // object; the condition scope can be set using WithConditions; if none of the
   266  // source objects have the conditions within the scope, no target condition is
   267  // generated.
   268  func aggregate(from []Getter, targetCondition string, options ...MergeOption) *metav1.Condition {
   269  	mergeOpt := &mergeOptions{
   270  		stepCounter: len(from),
   271  	}
   272  	for _, o := range options {
   273  		o(mergeOpt)
   274  	}
   275  
   276  	conditionsInScope := make([]localizedCondition, 0, len(from))
   277  	for i := range from {
   278  		conditions := from[i].GetConditions()
   279  		for i := range conditions {
   280  			c := conditions[i]
   281  			if mergeOpt.conditionTypes != nil {
   282  				found := false
   283  				for _, tt := range mergeOpt.conditionTypes {
   284  					if c.Type == tt {
   285  						found = true
   286  						break
   287  					}
   288  				}
   289  				if !found {
   290  					continue
   291  				}
   292  			}
   293  
   294  			conditionsInScope = append(conditionsInScope, localizedCondition{
   295  				Condition: &c,
   296  				Getter:    from[i],
   297  			})
   298  		}
   299  	}
   300  
   301  	// If it is required to add a counter only if a subset of condition exists,
   302  	// check if the conditions in scope are included in this subset or not.
   303  	if mergeOpt.addCounterOnlyIfConditionTypes != nil {
   304  		for _, c := range conditionsInScope {
   305  			found := false
   306  			for _, tt := range mergeOpt.addCounterOnlyIfConditionTypes {
   307  				if c.Type == tt {
   308  					found = true
   309  					break
   310  				}
   311  			}
   312  			if !found {
   313  				mergeOpt.addCounter = false
   314  				break
   315  			}
   316  		}
   317  	}
   318  
   319  	// If it is required to add a source ref only if a condition type exists,
   320  	// check if the conditions in scope are included in this subset or not.
   321  	if mergeOpt.addSourceRefIfConditionTypes != nil {
   322  		for _, c := range conditionsInScope {
   323  			found := false
   324  			for _, tt := range mergeOpt.addSourceRefIfConditionTypes {
   325  				if c.Type == tt {
   326  					found = true
   327  					break
   328  				}
   329  			}
   330  			if found {
   331  				mergeOpt.addSourceRef = true
   332  				break
   333  			}
   334  		}
   335  	}
   336  
   337  	return merge(conditionsInScope, targetCondition, mergeOpt)
   338  }
   339  

View as plain text