github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/lib/operatorstatus/builder.go (about)

     1  package operatorstatus
     2  
     3  import (
     4  	"reflect"
     5  
     6  	configv1 "github.com/openshift/api/config/v1"
     7  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     8  	"k8s.io/utils/clock"
     9  )
    10  
    11  // NewBuilder returns a builder for ClusterOperatorStatus.
    12  func NewBuilder(clock clock.Clock) *Builder {
    13  	return &Builder{
    14  		clock: clock,
    15  	}
    16  }
    17  
    18  // Builder helps build ClusterOperatorStatus with appropriate
    19  // ClusterOperatorStatusCondition and OperandVersion.
    20  type Builder struct {
    21  	clock  clock.Clock
    22  	status *configv1.ClusterOperatorStatus
    23  }
    24  
    25  // GetStatus returns the ClusterOperatorStatus built.
    26  func (b *Builder) GetStatus() *configv1.ClusterOperatorStatus {
    27  	return b.status
    28  }
    29  
    30  // WithProgressing sets an OperatorProgressing type condition.
    31  func (b *Builder) WithProgressing(status configv1.ConditionStatus, message string) *Builder {
    32  	b.init()
    33  	condition := &configv1.ClusterOperatorStatusCondition{
    34  		Type:               configv1.OperatorProgressing,
    35  		Status:             status,
    36  		Message:            message,
    37  		LastTransitionTime: metav1.NewTime(b.clock.Now()),
    38  	}
    39  
    40  	b.setCondition(condition)
    41  
    42  	return b
    43  }
    44  
    45  // WithDegraded sets an OperatorDegraded type condition.
    46  func (b *Builder) WithDegraded(status configv1.ConditionStatus) *Builder {
    47  	b.init()
    48  	condition := &configv1.ClusterOperatorStatusCondition{
    49  		Type:               configv1.OperatorDegraded,
    50  		Status:             status,
    51  		LastTransitionTime: metav1.NewTime(b.clock.Now()),
    52  	}
    53  
    54  	b.setCondition(condition)
    55  
    56  	return b
    57  }
    58  
    59  // WithAvailable sets an OperatorAvailable type condition.
    60  func (b *Builder) WithAvailable(status configv1.ConditionStatus, message, reason string) *Builder {
    61  	b.init()
    62  	condition := &configv1.ClusterOperatorStatusCondition{
    63  		Type:               configv1.OperatorAvailable,
    64  		Status:             status,
    65  		Message:            message,
    66  		Reason:             reason,
    67  		LastTransitionTime: metav1.NewTime(b.clock.Now()),
    68  	}
    69  
    70  	b.setCondition(condition)
    71  
    72  	return b
    73  }
    74  
    75  // WithUpgradeable sets an OperatorUpgradeable type condition.
    76  func (b *Builder) WithUpgradeable(status configv1.ConditionStatus, message string) *Builder {
    77  	b.init()
    78  	condition := &configv1.ClusterOperatorStatusCondition{
    79  		Type:               configv1.OperatorUpgradeable,
    80  		Status:             status,
    81  		Message:            message,
    82  		LastTransitionTime: metav1.NewTime(b.clock.Now()),
    83  	}
    84  
    85  	b.setCondition(condition)
    86  
    87  	return b
    88  }
    89  
    90  // WithVersion adds the specific version into the status.
    91  func (b *Builder) WithVersion(name, version string) *Builder {
    92  	b.init()
    93  
    94  	existing := b.findVersion(name)
    95  	if existing != nil {
    96  		existing.Version = version
    97  		return b
    98  	}
    99  
   100  	ov := configv1.OperandVersion{
   101  		Name:    name,
   102  		Version: version,
   103  	}
   104  	b.status.Versions = append(b.status.Versions, ov)
   105  
   106  	return b
   107  }
   108  
   109  // WithoutVersion removes the specified version from the existing status.
   110  func (b *Builder) WithoutVersion(name, version string) *Builder {
   111  	b.init()
   112  
   113  	versions := make([]configv1.OperandVersion, 0)
   114  
   115  	for _, v := range b.status.Versions {
   116  		if v.Name == name {
   117  			continue
   118  		}
   119  
   120  		versions = append(versions, v)
   121  	}
   122  
   123  	b.status.Versions = versions
   124  	return b
   125  }
   126  
   127  // WithRelatedObject adds the reference specified to the RelatedObjects list.
   128  func (b *Builder) WithRelatedObject(group, resource, namespace, name string) *Builder {
   129  	b.init()
   130  
   131  	reference := configv1.ObjectReference{
   132  		Group:     group,
   133  		Resource:  resource,
   134  		Namespace: namespace,
   135  		Name:      name,
   136  	}
   137  
   138  	b.setRelatedObject(reference)
   139  
   140  	return b
   141  }
   142  
   143  // WithoutRelatedObject removes the reference specified from the RelatedObjects list.
   144  func (b *Builder) WithoutRelatedObject(group, resource, namespace, name string) *Builder {
   145  	b.init()
   146  
   147  	reference := configv1.ObjectReference{
   148  		Group:     group,
   149  		Resource:  resource,
   150  		Namespace: namespace,
   151  		Name:      name,
   152  	}
   153  
   154  	related := make([]configv1.ObjectReference, 0)
   155  	for i := range b.status.RelatedObjects {
   156  		if reflect.DeepEqual(b.status.RelatedObjects[i], reference) {
   157  			continue
   158  		}
   159  
   160  		related = append(related, b.status.RelatedObjects[i])
   161  	}
   162  
   163  	b.status.RelatedObjects = related
   164  	return b
   165  }
   166  
   167  func (b *Builder) init() {
   168  	if b.status == nil {
   169  		b.status = &configv1.ClusterOperatorStatus{
   170  			Conditions:     []configv1.ClusterOperatorStatusCondition{},
   171  			Versions:       []configv1.OperandVersion{},
   172  			RelatedObjects: []configv1.ObjectReference{},
   173  		}
   174  	}
   175  }
   176  
   177  func (b *Builder) findCondition(conditionType configv1.ClusterStatusConditionType) *configv1.ClusterOperatorStatusCondition {
   178  	for i := range b.status.Conditions {
   179  		if b.status.Conditions[i].Type == conditionType {
   180  			return &b.status.Conditions[i]
   181  		}
   182  	}
   183  
   184  	return nil
   185  }
   186  
   187  func (b *Builder) setCondition(condition *configv1.ClusterOperatorStatusCondition) {
   188  	existing := b.findCondition(condition.Type)
   189  	if existing == nil {
   190  		b.status.Conditions = append(b.status.Conditions, *condition)
   191  		return
   192  	}
   193  
   194  	existing.Reason = condition.Reason
   195  	existing.Message = condition.Message
   196  
   197  	if existing.Status != condition.Status {
   198  		existing.Status = condition.Status
   199  		existing.LastTransitionTime = condition.LastTransitionTime
   200  	}
   201  }
   202  
   203  func (b *Builder) findVersion(name string) *configv1.OperandVersion {
   204  	for i := range b.status.Versions {
   205  		if b.status.Versions[i].Name == name {
   206  			return &b.status.Versions[i]
   207  		}
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  func (b *Builder) setRelatedObject(reference configv1.ObjectReference) {
   214  	for i := range b.status.RelatedObjects {
   215  		if reflect.DeepEqual(b.status.RelatedObjects[i], reference) {
   216  			return
   217  		}
   218  	}
   219  
   220  	b.status.RelatedObjects = append(b.status.RelatedObjects, reference)
   221  }