github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/reconcileresults/reconcile_results.go (about)

     1  // Copyright (c) 2020, 2022, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package reconcileresults
     5  
     6  import (
     7  	"reflect"
     8  
     9  	oamrt "github.com/crossplane/crossplane-runtime/apis/common/v1"
    10  	"github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1"
    11  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    12  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    13  )
    14  
    15  // ReconcileResults is used to collect the results of creating or updating child resources during reconciliation.
    16  // The contained arrays are parallel arrays
    17  type ReconcileResults struct {
    18  	Relations []v1alpha1.QualifiedResourceRelation
    19  	Results   []controllerutil.OperationResult
    20  	Errors    []error
    21  }
    22  
    23  // ContainsErrors scans the errors to determine if any errors were recorded.
    24  func (s *ReconcileResults) ContainsErrors() bool {
    25  	for _, err := range s.Errors {
    26  		if err != nil {
    27  			return true
    28  		}
    29  	}
    30  	return false
    31  }
    32  
    33  // ContainsUpdates scans the updates to determine if any updates were recorded.
    34  func (s *ReconcileResults) ContainsUpdates() bool {
    35  	for _, result := range s.Results {
    36  		if result != controllerutil.OperationResultNone {
    37  			return true
    38  		}
    39  	}
    40  	return false
    41  }
    42  
    43  // ContainsRelation determines if the reconcile result contains the provided relation.
    44  func (s *ReconcileResults) ContainsRelation(relation v1alpha1.QualifiedResourceRelation) bool {
    45  	for _, existing := range s.Relations {
    46  		if reflect.DeepEqual(relation, existing) {
    47  			return true
    48  		}
    49  	}
    50  	return false
    51  }
    52  
    53  // CreateConditionedStatus creates conditioned status for use in object status.
    54  // If no errors are found in the reconcile status a success condition is returned.
    55  // Otherwise reconcile errors statuses are returned for the first error.
    56  func (s *ReconcileResults) CreateConditionedStatus() oamrt.ConditionedStatus {
    57  	// Return the first error if there are any.
    58  	for _, err := range s.Errors {
    59  		if err != nil {
    60  			return oamrt.ConditionedStatus{Conditions: []oamrt.Condition{oamrt.ReconcileError(err)}}
    61  		}
    62  	}
    63  	// If no errors are found then return success.
    64  	return oamrt.ConditionedStatus{Conditions: []oamrt.Condition{oamrt.ReconcileSuccess()}}
    65  }
    66  
    67  // CreateResources creates a typed reference slice for use in an object status.
    68  func (s *ReconcileResults) CreateResources() []oamrt.TypedReference {
    69  	resources := []oamrt.TypedReference{}
    70  	for _, relation := range s.Relations {
    71  		resources = append(resources, oamrt.TypedReference{
    72  			APIVersion: relation.APIVersion,
    73  			Kind:       relation.Kind,
    74  			Name:       relation.Name,
    75  		})
    76  	}
    77  	return resources
    78  }
    79  
    80  // CreateRelations creates a qualified resource relation slice for use in an object status.
    81  func (s *ReconcileResults) CreateRelations() []v1alpha1.QualifiedResourceRelation {
    82  	// Copies the slice.
    83  	return append([]v1alpha1.QualifiedResourceRelation{}, s.Relations...)
    84  }
    85  
    86  // RecordOutcome records the outcome of an operation during a reconcile.
    87  func (s *ReconcileResults) RecordOutcome(rel v1alpha1.QualifiedResourceRelation, res controllerutil.OperationResult, err error) {
    88  	// Don't record the inability to update a deleted resource as an error.
    89  	if err == nil || !apierrors.IsNotFound(err) {
    90  		s.Relations = append(s.Relations, rel)
    91  		s.Results = append(s.Results, res)
    92  		s.Errors = append(s.Errors, err)
    93  	}
    94  }
    95  
    96  // RecordOutcomeIfError records the outcome of an operation during a reconcile only the err is non-nil.
    97  func (s *ReconcileResults) RecordOutcomeIfError(rel v1alpha1.QualifiedResourceRelation, res controllerutil.OperationResult, err error) {
    98  	// Don't record the inability to update a deleted resource as an error.
    99  	if err != nil && !apierrors.IsNotFound(err) {
   100  		s.Relations = append(s.Relations, rel)
   101  		s.Results = append(s.Results, res)
   102  		s.Errors = append(s.Errors, err)
   103  	}
   104  }
   105  
   106  // ConditionsEquivalent determines if two conditions are equivalent.
   107  // The type, status, reason and message are compared to determine equivalence.
   108  func ConditionsEquivalent(left *oamrt.Condition, right *oamrt.Condition) bool {
   109  	if left == nil && right == nil {
   110  		return true
   111  	}
   112  	if left == nil || right == nil {
   113  		return false
   114  	}
   115  	if left.Type != right.Type || left.Status != right.Status || left.Reason != right.Reason || left.Message != right.Message {
   116  		return false
   117  	}
   118  	return true
   119  }
   120  
   121  // ConditionedStatusEquivalent determines if two conditioned status are equivalent.
   122  // This is done by searching for all of the conditions from the left in the right.
   123  // Then the conditions in the right are searched for in the left.
   124  // False is returned at any point when a condition cannot be found.
   125  // True is returned if all conditions in the left can be found in the right and vice versa.
   126  func ConditionedStatusEquivalent(left *oamrt.ConditionedStatus, right *oamrt.ConditionedStatus) bool {
   127  	if left == nil && right == nil {
   128  		return true
   129  	}
   130  	if left == nil || right == nil {
   131  		return false
   132  	}
   133  	if len(left.Conditions) != len(right.Conditions) {
   134  		return false
   135  	}
   136  	for i := range left.Conditions {
   137  		if !ConditionsEquivalent(&left.Conditions[i], &right.Conditions[i]) {
   138  			return false
   139  		}
   140  	}
   141  	return true
   142  }