halkyon.io/api@v1.0.0-rc.6/v1beta1/commons.go (about) 1 package v1beta1 2 3 import ( 4 "fmt" 5 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 "k8s.io/apimachinery/pkg/runtime/schema" 7 "strings" 8 "time" 9 ) 10 11 const ( 12 // See https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ 13 NameLabelKey = "app.kubernetes.io/name" 14 VersionLabelKey = "app.kubernetes.io/version" 15 InstanceLabelKey = "app.kubernetes.io/instance" 16 PartOfLabelKey = "app.kubernetes.io/part-of" 17 ComponentLabelKey = "app.kubernetes.io/component" 18 ManagedByLabelKey = "app.kubernetes.io/managed-by" 19 RuntimeLabelKey = "app.openshift.io/runtime" 20 RuntimeVersionLabelKey = "app.openshift.io/version" 21 ) 22 23 type NameValuePair struct { 24 Name string `json:"name,omitempty"` 25 Value string `json:"value,omitempty"` 26 } 27 28 // DependentConditionType is a valid value for DependentCondition.Type 29 type DependentConditionType string 30 31 // These are valid dependent conditions. 32 const ( 33 // DependentReady means the dependent is able to service requests. 34 DependentReady DependentConditionType = "Ready" 35 // DependentPending means that the dependent is still processing. 36 DependentPending DependentConditionType = "Pending" 37 // DependentFailed means that the dependent is in error and probably requires user intervention to get back to working state. 38 DependentFailed DependentConditionType = "Failed" 39 ) 40 41 // DependentCondition contains details for the current condition of the associated DependentResource. 42 type DependentCondition struct { 43 // Type of the condition. 44 Type DependentConditionType `json:"type"` 45 // Type of the dependent associated with the condition. 46 DependentType schema.GroupVersionKind `json:"dependentType"` 47 // Name of the dependent associated with the condition. 48 DependentName string `json:"dependentName"` 49 // Records the last time the condition transitioned from one status to another. 50 // +optional 51 LastTransitionTime v1.Time `json:"lastTransitionTime,omitempty"` 52 // Unique, one-word, CamelCase reason for the condition's last transition. 53 // +optional 54 Reason string `json:"reason,omitempty"` 55 // Human-readable message indicating details about last transition. 56 // +optional 57 Message string `json:"message,omitempty"` 58 // Additional information that the condition wishes to convey/record as name-value pairs. 59 // +optional 60 Attributes []NameValuePair `json:"attributes,omitempty"` 61 } 62 63 const ( 64 // ReasonPending means the entity has been accepted by the system, but it is still being processed. This includes time 65 // being instantiated. 66 ReasonPending = "Pending" 67 // ReasonReady means the entity has been instantiated to a node and all of its dependencies are available. The 68 // entity is able to process requests. 69 ReasonReady = "Ready" 70 // ReasonFailed means that the entity or some of its dependencies have failed and cannot be salvaged without user 71 // intervention. 72 ReasonFailed = "Failed" 73 ) 74 75 type Status struct { 76 LastUpdate v1.Time `json:"lastUpdate,omitempty"` 77 Reason string `json:"reason,omitempty"` 78 Message string `json:"message,omitempty"` 79 Conditions []DependentCondition `json:"conditions,omitempty"` 80 } 81 82 func (in *Status) GetConditionsWith(gvk schema.GroupVersionKind) []DependentCondition { 83 if gvk.Empty() { 84 return []DependentCondition{} 85 } 86 87 conditions := make([]DependentCondition, 0, len(in.Conditions)) 88 for _, condition := range in.Conditions { 89 if condition.DependentType == gvk { 90 conditions = append(conditions, condition) 91 } 92 } 93 return conditions 94 } 95 96 func (in *Status) GetConditionFor(name string, gvk schema.GroupVersionKind) (existingOrNew *DependentCondition) { 97 _, condition := in.indexAndConditionWith(name, gvk) 98 return condition 99 } 100 101 func (in *Status) indexAndConditionWith(name string, gvk schema.GroupVersionKind) (index int, existingOrNew *DependentCondition) { 102 if len(name) == 0 || gvk.Empty() { 103 panic(fmt.Errorf("a condition needs a name and a gvk")) 104 } 105 if in.Conditions == nil { 106 in.Conditions = make([]DependentCondition, 0, 15) 107 } 108 for i, condition := range in.Conditions { 109 if condition.DependentName == name && condition.DependentType == gvk { 110 return i, &condition 111 } 112 } 113 existingOrNew = &DependentCondition{ 114 DependentType: gvk, 115 DependentName: name, 116 } 117 index = len(in.Conditions) 118 in.Conditions = append(in.Conditions, *existingOrNew) 119 return 120 } 121 122 // SetCondition sets the given condition on the Status, returning true if the status has been modified as a result 123 func (in *Status) SetCondition(condition *DependentCondition) (updated bool) { 124 if condition == nil { 125 return false 126 } 127 128 // if, for some reason, the index is not set on the condition, retrieve the condition again from the array as this sets the index 129 index, previous := in.indexAndConditionWith(condition.DependentName, condition.DependentType) 130 if previous == nil || condition.Type != previous.Type || condition.Message != previous.Message { 131 condition.Reason = string(condition.Type) 132 now := v1.NewTime(time.Now()) 133 condition.LastTransitionTime = now 134 in.LastUpdate = now 135 in.Conditions[index] = *condition // update the array with the new condition 136 updated = true 137 } 138 139 // re-compute overall status only if the set condition has changed or if we don't already have an overall status 140 if updated || len(in.Reason) == 0 { 141 overall := ReasonReady 142 conditionMessages := make([]string, 0, len(in.Conditions)) 143 for _, c := range in.Conditions { 144 // if the condition isn't ready, then the overall status should be pending 145 if !c.IsReady() { 146 if len(c.Message) > 0 { 147 conditionMessages = append(conditionMessages, c.Message) 148 } 149 overall = ReasonPending 150 } 151 // if the condition is failed, then the overall status should be failed 152 if c.IsFailed() { 153 overall = ReasonFailed 154 } 155 } 156 if in.Reason != overall { 157 in.Reason = overall 158 updated = true 159 } 160 msg := strings.Join(conditionMessages, ", ") 161 if in.Message != msg { 162 in.Message = msg 163 updated = true 164 } 165 } 166 167 return 168 } 169 170 func (in *DependentCondition) GetAttribute(name string) string { 171 for _, attribute := range in.Attributes { 172 if attribute.Name == name { 173 return attribute.Value 174 } 175 } 176 return "" 177 } 178 179 func (in *DependentCondition) SetAttribute(name, value string) string { 180 for i, attribute := range in.Attributes { 181 if attribute.Name == name { 182 in.Attributes[i] = NameValuePair{ 183 Name: attribute.Name, 184 Value: value, 185 } 186 return attribute.Value 187 } 188 } 189 in.Attributes = append(in.Attributes, NameValuePair{Name: name, Value: value}) 190 return "" 191 } 192 193 func (in *DependentCondition) IsReady() bool { 194 return in.Type == DependentReady 195 } 196 197 func (in *DependentCondition) IsFailed() bool { 198 return in.Type == DependentFailed 199 } 200 201 type StatusAware interface { 202 GetStatus() Status 203 SetStatus(status Status) 204 Handle(err error) (bool, Status) 205 } 206 207 func (in *DependentCondition) DeepCopyInto(out *DependentCondition) { 208 *out = *in 209 out.DependentType = in.DependentType 210 in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) 211 if in.Attributes != nil { 212 in, out := &in.Attributes, &out.Attributes 213 *out = make([]NameValuePair, len(*in)) 214 copy(*out, *in) 215 } 216 return 217 } 218 219 func (in *DependentCondition) DeepCopy() *DependentCondition { 220 if in == nil { 221 return nil 222 } 223 out := new(DependentCondition) 224 in.DeepCopyInto(out) 225 return out 226 } 227 228 func (in *Status) DeepCopyInto(out *Status) { 229 *out = *in 230 in.LastUpdate.DeepCopyInto(&out.LastUpdate) 231 if in.Conditions != nil { 232 in, out := &in.Conditions, &out.Conditions 233 *out = make([]DependentCondition, len(*in)) 234 for i := range *in { 235 (*in)[i].DeepCopyInto(&(*out)[i]) 236 } 237 } 238 return 239 } 240 241 func (in *Status) DeepCopy() *Status { 242 if in == nil { 243 return nil 244 } 245 out := new(Status) 246 in.DeepCopyInto(out) 247 return out 248 }