/
status.go
144 lines (125 loc) · 5.79 KB
/
status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package v1helpers
import (
"bytes"
"fmt"
"strings"
"time"
"k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/json"
configv1 "github.com/openshift/api/config/v1"
)
// SetStatusCondition sets the corresponding condition in conditions to newCondition.
func SetStatusCondition(conditions *[]configv1.ClusterOperatorStatusCondition, newCondition configv1.ClusterOperatorStatusCondition) {
if conditions == nil {
conditions = &[]configv1.ClusterOperatorStatusCondition{}
}
existingCondition := FindStatusCondition(*conditions, newCondition.Type)
if existingCondition == nil {
newCondition.LastTransitionTime = metav1.NewTime(time.Now())
*conditions = append(*conditions, newCondition)
return
}
if existingCondition.Status != newCondition.Status {
existingCondition.Status = newCondition.Status
existingCondition.LastTransitionTime = metav1.NewTime(time.Now())
}
existingCondition.Reason = newCondition.Reason
existingCondition.Message = newCondition.Message
}
// RemoveStatusCondition removes the corresponding conditionType from conditions.
func RemoveStatusCondition(conditions *[]configv1.ClusterOperatorStatusCondition, conditionType configv1.ClusterStatusConditionType) {
if conditions == nil {
conditions = &[]configv1.ClusterOperatorStatusCondition{}
}
newConditions := []configv1.ClusterOperatorStatusCondition{}
for _, condition := range *conditions {
if condition.Type != conditionType {
newConditions = append(newConditions, condition)
}
}
*conditions = newConditions
}
// FindStatusCondition finds the conditionType in conditions.
func FindStatusCondition(conditions []configv1.ClusterOperatorStatusCondition, conditionType configv1.ClusterStatusConditionType) *configv1.ClusterOperatorStatusCondition {
for i := range conditions {
if conditions[i].Type == conditionType {
return &conditions[i]
}
}
return nil
}
// GetStatusDiff returns a string representing change in condition status in human readable form.
func GetStatusDiff(oldStatus configv1.ClusterOperatorStatus, newStatus configv1.ClusterOperatorStatus) string {
messages := []string{}
for _, newCondition := range newStatus.Conditions {
existingStatusCondition := FindStatusCondition(oldStatus.Conditions, newCondition.Type)
if existingStatusCondition == nil {
messages = append(messages, fmt.Sprintf("%s set to %s (%q)", newCondition.Type, newCondition.Status, newCondition.Message))
continue
}
if existingStatusCondition.Status != newCondition.Status {
messages = append(messages, fmt.Sprintf("%s changed from %s to %s (%q)", existingStatusCondition.Type, existingStatusCondition.Status, newCondition.Status, newCondition.Message))
continue
}
if existingStatusCondition.Message != newCondition.Message {
messages = append(messages, fmt.Sprintf("%s message changed from %q to %q", existingStatusCondition.Type, existingStatusCondition.Message, newCondition.Message))
}
}
for _, oldCondition := range oldStatus.Conditions {
// This should not happen. It means we removed old condition entirely instead of just changing its status
if c := FindStatusCondition(newStatus.Conditions, oldCondition.Type); c == nil {
messages = append(messages, fmt.Sprintf("%s was removed", oldCondition.Type))
}
}
if !equality.Semantic.DeepEqual(oldStatus.RelatedObjects, newStatus.RelatedObjects) {
messages = append(messages, fmt.Sprintf("status.relatedObjects changed from %q to %q", oldStatus.RelatedObjects, newStatus.RelatedObjects))
}
if !equality.Semantic.DeepEqual(oldStatus.Extension, newStatus.Extension) {
messages = append(messages, fmt.Sprintf("status.extension changed from %q to %q", oldStatus.Extension, newStatus.Extension))
}
if !equality.Semantic.DeepEqual(oldStatus.Versions, newStatus.Versions) {
messages = append(messages, fmt.Sprintf("status.versions changed from %q to %q", oldStatus.Versions, newStatus.Versions))
}
if len(messages) == 0 {
// ignore errors
originalJSON := &bytes.Buffer{}
json.NewEncoder(originalJSON).Encode(oldStatus)
newJSON := &bytes.Buffer{}
json.NewEncoder(newJSON).Encode(newStatus)
messages = append(messages, diff.StringDiff(originalJSON.String(), newJSON.String()))
}
return strings.Join(messages, ",")
}
// IsStatusConditionTrue returns true when the conditionType is present and set to `configv1.ConditionTrue`
func IsStatusConditionTrue(conditions []configv1.ClusterOperatorStatusCondition, conditionType configv1.ClusterStatusConditionType) bool {
return IsStatusConditionPresentAndEqual(conditions, conditionType, configv1.ConditionTrue)
}
// IsStatusConditionFalse returns true when the conditionType is present and set to `configv1.ConditionFalse`
func IsStatusConditionFalse(conditions []configv1.ClusterOperatorStatusCondition, conditionType configv1.ClusterStatusConditionType) bool {
return IsStatusConditionPresentAndEqual(conditions, conditionType, configv1.ConditionFalse)
}
// IsStatusConditionPresentAndEqual returns true when conditionType is present and equal to status.
func IsStatusConditionPresentAndEqual(conditions []configv1.ClusterOperatorStatusCondition, conditionType configv1.ClusterStatusConditionType, status configv1.ConditionStatus) bool {
for _, condition := range conditions {
if condition.Type == conditionType {
return condition.Status == status
}
}
return false
}
// IsStatusConditionNotIn returns true when the conditionType does not match the status.
func IsStatusConditionNotIn(conditions []configv1.ClusterOperatorStatusCondition, conditionType configv1.ClusterStatusConditionType, status ...configv1.ConditionStatus) bool {
for _, condition := range conditions {
if condition.Type == conditionType {
for _, s := range status {
if s == condition.Status {
return false
}
}
return true
}
}
return true
}