forked from crossplane-contrib/function-auto-ready
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfn.go
More file actions
126 lines (102 loc) · 4.15 KB
/
fn.go
File metadata and controls
126 lines (102 loc) · 4.15 KB
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
package main
import (
"context"
corev1 "k8s.io/api/core/v1"
"github.com/crossplane/function-sdk-go/errors"
"github.com/crossplane/function-sdk-go/logging"
fnv1 "github.com/crossplane/function-sdk-go/proto/v1"
"github.com/crossplane/function-sdk-go/request"
"github.com/crossplane/function-sdk-go/resource"
"github.com/crossplane/function-sdk-go/response"
xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"
"github.com/crossplane/function-auto-ready/healthchecks"
)
// Function returns whatever response you ask it to.
type Function struct {
fnv1.UnimplementedFunctionRunnerServiceServer
log logging.Logger
}
// RunFunction runs the Function.
func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) {
f.log.Info("Running Function", "tag", req.GetMeta().GetTag())
rsp := response.To(req, response.DefaultTTL)
oxr, err := request.GetObservedCompositeResource(req)
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot get observed composite resource from %T", req))
return rsp, nil
}
log := f.log.WithValues(
"xr-apiversion", oxr.Resource.GetAPIVersion(),
"xr-kind", oxr.Resource.GetKind(),
"xr-name", oxr.Resource.GetName(),
)
observed, err := request.GetObservedComposedResources(req)
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot get observed composed resources from %T", req))
return rsp, nil
}
desired, err := request.GetDesiredComposedResources(req)
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot get desired composed resources from %T", req))
return rsp, nil
}
f.log.Debug("Found desired resources", "count", len(desired))
// First, mark standard Kubernetes resources as ready using resource-specific health checks
for name, dr := range desired {
log := log.WithValues("composed-resource-name", name)
// Skip if resource doesn't exist yet
or, ok := observed[name]
if !ok {
continue
}
// Skip if readiness already explicitly set
if dr.Ready != resource.ReadyUnspecified {
continue
}
// Check if this resource type has a registered health check
// Get GVK from the unstructured object (apiVersion and kind fields)
// composed.Unstructured embeds unstructured.Unstructured, so we can use it directly
gvk := or.Resource.GroupVersionKind()
if healthCheck := healthchecks.GetHealthCheck(gvk); healthCheck != nil {
log.Debug("Using resource-specific health check", "gvk", gvk.String())
if healthCheck(&or.Resource.Unstructured) {
log.Info("Marked resource as ready via resource-specific health check", "gvk", gvk.String())
dr.Ready = resource.ReadyTrue
}
}
}
// Second, check remaining resources using the Ready status condition
for name, dr := range desired {
log := log.WithValues("composed-resource-name", name)
// If this desired resource doesn't exist in the observed resources, it
// can't be ready because it doesn't yet exist.
or, ok := observed[name]
if !ok {
log.Debug("Ignoring desired resource that does not appear in observed resources")
continue
}
// A previous Function in the pipeline either said this resource was
// explicitly ready, or explicitly not ready. We only want to
// automatically determine readiness for desired resources where no
// other Function has an opinion about their readiness.
if dr.Ready != resource.ReadyUnspecified {
log.Debug("Ignoring desired resource that already has explicit readiness", "ready", dr.Ready)
continue
}
// Now we know this resource exists, and no Function that ran before us
// has an opinion about whether it's ready.
log.Debug("Found desired resource with unknown readiness")
// If this observed resource has a status condition with type: Ready,
// status: True, we set its readiness to true.
c := or.Resource.GetCondition(xpv1.TypeReady)
if c.Status == corev1.ConditionTrue {
log.Info("Automatically determined that composed resource is ready")
dr.Ready = resource.ReadyTrue
}
}
if err := response.SetDesiredComposedResources(rsp, desired); err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot set desired composed resources from %T", req))
return rsp, nil
}
return rsp, nil
}