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 }