istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/autoregistration/internal/health/controller.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package health 16 17 import ( 18 "google.golang.org/protobuf/types/known/timestamppb" 19 20 "istio.io/api/meta/v1alpha1" 21 "istio.io/istio/pilot/pkg/autoregistration/internal/state" 22 "istio.io/istio/pilot/pkg/model" 23 "istio.io/istio/pilot/pkg/model/status" 24 "istio.io/istio/pkg/kube/controllers" 25 istiolog "istio.io/istio/pkg/log" 26 ) 27 28 var log = istiolog.RegisterScope("wle", "wle controller debugging") 29 30 type HealthEvent struct { 31 // whether or not the agent thought the target is healthy 32 Healthy bool `json:"healthy,omitempty"` 33 // error message propagated 34 Message string `json:"errMessage,omitempty"` 35 } 36 37 type HealthCondition struct { 38 proxy *model.Proxy 39 entryName string 40 condition *v1alpha1.IstioCondition 41 } 42 43 // Controller knows how to update health status of a workload. 44 type Controller struct { 45 stateStore *state.Store 46 47 // healthCondition is a fifo queue used for updating health check status 48 healthCondition controllers.Queue 49 } 50 51 // NewController returns a new Controller instance. 52 func NewController(stateStore *state.Store, maxRetries int) *Controller { 53 c := &Controller{ 54 stateStore: stateStore, 55 } 56 c.healthCondition = controllers.NewQueue("healthcheck", 57 controllers.WithMaxAttempts(maxRetries), 58 controllers.WithGenericReconciler(c.updateWorkloadEntryHealth)) 59 return c 60 } 61 62 func (c *Controller) Run(stop <-chan struct{}) { 63 c.healthCondition.Run(stop) 64 } 65 66 // QueueWorkloadEntryHealth enqueues the associated WorkloadEntries health status. 67 func (c *Controller) QueueWorkloadEntryHealth(proxy *model.Proxy, event HealthEvent) { 68 // we assume that the workload entry exists 69 // if auto registration does not exist, try looking 70 // up in NodeMetadata 71 entryName, _ := proxy.WorkloadEntry() 72 if entryName == "" { 73 log.Errorf("unable to derive WorkloadEntry for health update for %v", proxy.ID) 74 return 75 } 76 77 condition := transformHealthEvent(proxy, entryName, event) 78 c.healthCondition.Add(condition) 79 } 80 81 func transformHealthEvent(proxy *model.Proxy, entryName string, event HealthEvent) HealthCondition { 82 cond := &v1alpha1.IstioCondition{ 83 Type: status.ConditionHealthy, 84 // last probe and transition are the same because 85 // we only send on transition in the agent 86 LastProbeTime: timestamppb.Now(), 87 LastTransitionTime: timestamppb.Now(), 88 } 89 out := HealthCondition{ 90 proxy: proxy, 91 entryName: entryName, 92 condition: cond, 93 } 94 if event.Healthy { 95 cond.Status = status.StatusTrue 96 return out 97 } 98 cond.Status = status.StatusFalse 99 cond.Message = event.Message 100 return out 101 } 102 103 // updateWorkloadEntryHealth updates the associated WorkloadEntries health status 104 // based on the corresponding health check performed by istio-agent. 105 func (c *Controller) updateWorkloadEntryHealth(obj any) error { 106 condition := obj.(HealthCondition) 107 return c.stateStore.UpdateHealth(condition.proxy.ID, condition.entryName, condition.proxy.Metadata.Namespace, condition.condition) 108 }