Skip to content

Commit 2f71d01

Browse files
authored
Merge pull request #1068 from fluxcd/cel-improvements
runtime/cel: improve and simplify status reader
2 parents 572c0fc + 9307c2c commit 2f71d01

File tree

5 files changed

+240
-300
lines changed

5 files changed

+240
-300
lines changed

runtime/cel/status_poller.go

Lines changed: 0 additions & 61 deletions
This file was deleted.

runtime/cel/status_poller_test.go

Lines changed: 0 additions & 208 deletions
This file was deleted.

runtime/cel/status_reader.go

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package cel
1818

1919
import (
2020
"context"
21+
"fmt"
2122

2223
"github.com/fluxcd/cli-utils/pkg/kstatus/polling/engine"
2324
"github.com/fluxcd/cli-utils/pkg/kstatus/polling/event"
@@ -27,45 +28,85 @@ import (
2728
"k8s.io/apimachinery/pkg/api/meta"
2829
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2930
"k8s.io/apimachinery/pkg/runtime/schema"
31+
32+
"github.com/fluxcd/pkg/apis/kustomize"
3033
)
3134

3235
// StatusReader implements the engine.StatusReader interface for a specific GroupKind and
3336
// set of healthcheck expressions.
3437
type StatusReader struct {
35-
genericStatusReader engine.StatusReader
36-
gk schema.GroupKind
38+
mapper meta.RESTMapper
39+
evaluators map[schema.GroupKind]*StatusEvaluator
3740
}
3841

3942
// NewStatusReader returns a new StatusReader for the given GroupKind and healthcheck expressions.
40-
// The context is used to control the execution of the underlying operations performed by the
41-
// the reader.
42-
func NewStatusReader(ctx context.Context, mapper meta.RESTMapper, gk schema.GroupKind,
43-
se *StatusEvaluator) engine.StatusReader {
44-
45-
statusFunc := func(u *unstructured.Unstructured) (*status.Result, error) {
46-
return se.Evaluate(ctx, u)
43+
func NewStatusReader(healthchecks []kustomize.CustomHealthCheck) (func(meta.RESTMapper) engine.StatusReader, error) {
44+
// Build evaluators map.
45+
evaluators := make(map[schema.GroupKind]*StatusEvaluator, len(healthchecks))
46+
for i, hc := range healthchecks {
47+
gk := schema.FromAPIVersionAndKind(hc.APIVersion, hc.Kind).GroupKind()
48+
if _, ok := evaluators[gk]; ok {
49+
return nil, fmt.Errorf(
50+
"duplicate custom health check for GroupKind %s at healthchecks[%d]", gk.String(), i)
51+
}
52+
se, err := NewStatusEvaluator(&hc.HealthCheckExpressions)
53+
if err != nil {
54+
return nil, fmt.Errorf(
55+
"failed to create custom status evaluator for healthchecks[%d]: %w", i, err)
56+
}
57+
evaluators[gk] = se
4758
}
4859

49-
genericStatusReader := kstatusreaders.NewGenericStatusReader(mapper, statusFunc)
50-
return &StatusReader{
51-
genericStatusReader: genericStatusReader,
52-
gk: gk,
53-
}
60+
return func(mapper meta.RESTMapper) engine.StatusReader {
61+
return &StatusReader{
62+
mapper: mapper,
63+
evaluators: evaluators,
64+
}
65+
}, nil
5466
}
5567

5668
// Supports returns true if the StatusReader supports the given GroupKind.
5769
func (g *StatusReader) Supports(gk schema.GroupKind) bool {
58-
return gk == g.gk
70+
_, ok := g.evaluators[gk]
71+
return ok
5972
}
6073

6174
// ReadStatus reads the status of the resource with the given metadata.
6275
func (g *StatusReader) ReadStatus(ctx context.Context, reader engine.ClusterReader,
6376
resource object.ObjMetadata) (*event.ResourceStatus, error) {
64-
return g.genericStatusReader.ReadStatus(ctx, reader, resource)
77+
78+
if !g.Supports(resource.GroupKind) {
79+
return nil, fmt.Errorf("the GroupKind %s is not supported", resource.GroupKind.String())
80+
}
81+
82+
return g.genericStatusReader(ctx, resource.GroupKind).ReadStatus(ctx, reader, resource)
6583
}
6684

6785
// ReadStatusForObject reads the status of the given resource.
6886
func (g *StatusReader) ReadStatusForObject(ctx context.Context, reader engine.ClusterReader,
6987
resource *unstructured.Unstructured) (*event.ResourceStatus, error) {
70-
return g.genericStatusReader.ReadStatusForObject(ctx, reader, resource)
88+
89+
// Compute GroupKind.
90+
apiVersion, ok, _ := unstructured.NestedFieldCopy(resource.Object, "apiVersion")
91+
if !ok {
92+
return nil, fmt.Errorf("resource is missing apiVersion field")
93+
}
94+
kind, ok, _ := unstructured.NestedFieldCopy(resource.Object, "kind")
95+
if !ok {
96+
return nil, fmt.Errorf("resource is missing kind field")
97+
}
98+
gk := schema.FromAPIVersionAndKind(apiVersion.(string), kind.(string)).GroupKind()
99+
if !g.Supports(gk) {
100+
return nil, fmt.Errorf("the GroupKind %s is not supported", gk.String())
101+
}
102+
103+
return g.genericStatusReader(ctx, gk).ReadStatusForObject(ctx, reader, resource)
104+
}
105+
106+
// genericStatusReader returns the underlying generic status reader.
107+
func (g *StatusReader) genericStatusReader(ctx context.Context, gk schema.GroupKind) engine.StatusReader {
108+
statusFunc := func(u *unstructured.Unstructured) (*status.Result, error) {
109+
return g.evaluators[gk].Evaluate(ctx, u)
110+
}
111+
return kstatusreaders.NewGenericStatusReader(g.mapper, statusFunc)
71112
}

0 commit comments

Comments
 (0)