Change health check from WorkloadReference to CrossNamespaceObjectReference

This commit is contained in:
Philip Laine 2020-09-07 23:31:31 +02:00
parent d711b699bb
commit ea627e3448
5 changed files with 47 additions and 79 deletions

View File

@ -17,7 +17,6 @@ limitations under the License.
package v1alpha1
import (
"fmt"
"time"
corev1 "k8s.io/api/core/v1"
@ -54,7 +53,7 @@ type KustomizationSpec struct {
// A list of workloads (Deployments, DaemonSets and StatefulSets)
// to be included in the health assessment.
// +optional
HealthChecks []WorkloadReference `json:"healthChecks,omitempty"`
HealthChecks []CrossNamespaceObjectReference `json:"healthChecks,omitempty"`
// The Kubernetes service account used for applying the kustomization.
// +optional
@ -81,25 +80,6 @@ type KustomizationSpec struct {
Validation string `json:"validation,omitempty"`
}
// WorkloadReference defines a reference to a Deployment, DaemonSet or StatefulSet.
type WorkloadReference struct {
// GroupKind is the type of resource being referenced.
// +required
GroupKind metav1.GroupKind `json:"groupKind"`
// Name is the name of resource being referenced.
// +required
Name string `json:"name"`
// Namespace is the namespace of resource being referenced.
// +required
Namespace string `json:"namespace"`
}
func (w WorkloadReference) String() string {
return fmt.Sprintf("%s/%s/%s", w.GroupKind.String(), w.Namespace, w.Name)
}
// ServiceAccount defines a reference to a Kubernetes service account.
type ServiceAccount struct {
// Name is the name of the service account being referenced.

View File

@ -24,7 +24,6 @@ type CrossNamespaceObjectReference struct {
APIVersion string `json:"apiVersion,omitempty"`
// Kind of the referent
// +kubebuilder:validation:Enum=GitRepository
// +required
Kind string `json:"kind"`

View File

@ -152,7 +152,7 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
out.Interval = in.Interval
if in.HealthChecks != nil {
in, out := &in.HealthChecks, &out.HealthChecks
*out = make([]WorkloadReference, len(*in))
*out = make([]CrossNamespaceObjectReference, len(*in))
copy(*out, *in)
}
if in.ServiceAccount != nil {
@ -263,19 +263,3 @@ func (in *SnapshotEntry) DeepCopy() *SnapshotEntry {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkloadReference) DeepCopyInto(out *WorkloadReference) {
*out = *in
out.GroupKind = in.GroupKind
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkloadReference.
func (in *WorkloadReference) DeepCopy() *WorkloadReference {
if in == nil {
return nil
}
out := new(WorkloadReference)
in.DeepCopyInto(out)
return out
}

View File

@ -79,30 +79,24 @@ spec:
description: A list of workloads (Deployments, DaemonSets and StatefulSets)
to be included in the health assessment.
items:
description: WorkloadReference defines a reference to a Deployment,
DaemonSet or StatefulSet.
description: CrossNamespaceObjectReference contains enough information
to let you locate the typed referenced object at cluster level
properties:
groupKind:
description: GroupKind is the type of resource being referenced.
properties:
group:
type: string
kind:
type: string
required:
- group
- kind
type: object
apiVersion:
description: API version of the referent
type: string
kind:
description: Kind of the referent
type: string
name:
description: Name is the name of resource being referenced.
description: Name of the referent
type: string
namespace:
description: Namespace is the namespace of resource being referenced.
description: Namespace of the referent
type: string
required:
- groupKind
- kind
- name
- namespace
type: object
type: array
interval:
@ -139,8 +133,6 @@ spec:
type: string
kind:
description: Kind of the referent
enum:
- GitRepository
type: string
name:
description: Name of the referent

View File

@ -621,25 +621,34 @@ func (r *KustomizationReconciler) prune(kustomization kustomizev1.Kustomization,
return nil
}
func toObjMetadata(wr []kustomizev1.WorkloadReference) []object.ObjMetadata {
func toObjMetadata(cr []kustomizev1.CrossNamespaceObjectReference) ([]object.ObjMetadata, error) {
oo := []object.ObjMetadata{}
for _, w := range wr {
oo = append(oo, object.ObjMetadata{
Name: w.Name,
Namespace: w.Namespace,
GroupKind: schema.GroupKind{
Group: w.GroupKind.Group,
Kind: w.GroupKind.Kind,
},
})
for _, c := range cr {
// For backwards compatibility
if c.APIVersion == "" {
c.APIVersion = "apps/v1"
}
gv, err := schema.ParseGroupVersion(c.APIVersion)
if err != nil {
return []object.ObjMetadata{}, err
}
gk := schema.GroupKind{Group: gv.Group, Kind: c.Kind}
o, err := object.CreateObjMetadata(c.Namespace, c.Name, gk)
if err != nil {
return []object.ObjMetadata{}, err
}
oo = append(oo, o)
}
return oo
return oo, nil
}
func toHealthySet(wr []kustomizev1.WorkloadReference) map[string]bool {
func toHealthySet(oo []object.ObjMetadata) map[string]bool {
hs := map[string]bool{}
for _, w := range wr {
hs[w.String()] = false
for _, o := range oo {
hs[o.String()] = false
}
return hs
}
@ -659,31 +668,35 @@ func (r *KustomizationReconciler) checkHealth(kustomization kustomizev1.Kustomiz
return nil
}
objMetadata, err := toObjMetadata(kustomization.Spec.HealthChecks)
if err != nil {
return err
}
timeout := kustomization.GetTimeout() + (time.Second * 1)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
opts := polling.Options{PollInterval: 500 * time.Millisecond, UseCache: true}
healthySet := toHealthySet(kustomization.Spec.HealthChecks)
eventsChan := r.Poller.Poll(ctx, toObjMetadata(kustomization.Spec.HealthChecks), opts)
healthySet := toHealthySet(objMetadata)
eventsChan := r.Poller.Poll(ctx, objMetadata, opts)
for {
select {
case <-ctx.Done():
notHealthy := filterHealthSet(healthySet, false)
return fmt.Errorf("Health check timeout for [%v]", strings.Join(notHealthy, ", "))
return fmt.Errorf("Health check timed out for [%v]", strings.Join(notHealthy, ", "))
case e := <-eventsChan:
switch e.EventType {
case event.ResourceUpdateEvent:
id := fmt.Sprintf("%s/%s/%s", e.Resource.Identifier.GroupKind.String(), e.Resource.Identifier.Namespace, e.Resource.Identifier.Name)
if e.Resource.Status == status.CurrentStatus {
healthySet[id] = true
healthySet[e.Resource.Identifier.String()] = true
r.Log.WithValues(
strings.ToLower(kustomization.Kind),
fmt.Sprintf("%s/%s", kustomization.GetNamespace(), kustomization.GetName()),
).Info(fmt.Sprintf("Health check passed for %s", id))
).Info(fmt.Sprintf("Health check passed for %s", e.Resource.Identifier.String()))
} else {
healthySet[id] = false
healthySet[e.Resource.Identifier.String()] = false
}
case event.ErrorEvent:
return e.Error