Skip to content

Commit c1132df

Browse files
author
Paul Carlton
authored
Change conditons and add events (#155)
Change conditions to support wait for status and add events Also check dependencies before checking if apply is needed.
1 parent fe3a082 commit c1132df

File tree

5 files changed

+63
-159
lines changed

5 files changed

+63
-159
lines changed

controllers/addons_controller.go

+32-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ import (
3131
"k8s.io/apimachinery/pkg/runtime"
3232
"k8s.io/apimachinery/pkg/types"
3333
"k8s.io/client-go/kubernetes"
34+
kscheme "k8s.io/client-go/kubernetes/scheme"
35+
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
3436
"k8s.io/client-go/rest"
37+
"k8s.io/client-go/tools/record"
3538
ctrl "sigs.k8s.io/controller-runtime"
3639
"sigs.k8s.io/controller-runtime/pkg/client"
3740
"sigs.k8s.io/controller-runtime/pkg/controller"
@@ -177,6 +180,22 @@ type AddonsLayerReconciler struct {
177180
Applier apply.LayerApplier
178181
Repos repos.Repos
179182
Metrics metrics.Metrics
183+
Recorder record.EventRecorder
184+
}
185+
186+
// EventRecorder returns an EventRecorder type that can be
187+
// used to post Events to different object's lifecycles.
188+
func eventRecorder(
189+
kubeClient kubernetes.Interface) record.EventRecorder {
190+
eventBroadcaster := record.NewBroadcaster()
191+
//eventBroadcaster.StartLogging(setupLog.Infof)
192+
eventBroadcaster.StartRecordingToSink(
193+
&typedcorev1.EventSinkImpl{
194+
Interface: kubeClient.CoreV1().Events("")})
195+
recorder := eventBroadcaster.NewRecorder(
196+
kscheme.Scheme,
197+
corev1.EventSource{Component: "kraan-controller"})
198+
return recorder
180199
}
181200

182201
// NewReconciler returns an AddonsLayerReconciler instance
@@ -193,6 +212,7 @@ func NewReconciler(config *rest.Config, client client.Client, logger logr.Logger
193212
if err != nil {
194213
return nil, errors.WithMessagef(err, "%s - failed to create reconciler", logging.CallerStr(logging.Me))
195214
}
215+
reconciler.Recorder = eventRecorder(reconciler.k8client)
196216
reconciler.Context = context.Background()
197217
reconciler.Applier, err = apply.NewApplier(client, logger.WithName("applier"), scheme)
198218
if err != nil {
@@ -246,6 +266,11 @@ func (r *AddonsLayerReconciler) processApply(l layers.Layer) (statusReconciled b
246266
ctx := r.Context
247267
applier := r.Applier
248268

269+
if !l.DependenciesDeployed() {
270+
l.SetRequeue()
271+
return true, nil
272+
}
273+
249274
applyIsRequired, err := applier.ApplyIsRequired(ctx, l)
250275
if err != nil {
251276
return false, errors.WithMessagef(err, "%s - check if apply is required failed", logging.CallerStr(logging.Me))
@@ -496,13 +521,18 @@ func (r *AddonsLayerReconciler) Reconcile(req ctrl.Request) (res ctrl.Result, er
496521

497522
log := r.Log.WithValues("layer", req.NamespacedName.Name)
498523

499-
l := layers.CreateLayer(ctx, r.Client, r.k8client, log, addonsLayer)
524+
l := layers.CreateLayer(ctx, r.Client, r.k8client, log, r.Recorder, r.Scheme, addonsLayer)
500525
deployedRevision, err := r.processAddonLayer(l)
501526
if err != nil {
502527
l.StatusUpdate(kraanv1alpha1.FailedCondition, kraanv1alpha1.AddonsLayerFailedReason, errors.Cause(err).Error())
503528
log.Error(err, "failed to process addons layer", logging.GetFunctionAndSource(logging.MyCaller)...)
504529
}
505530

531+
if l.GetSpec().Version != l.GetFullStatus().Version {
532+
l.SetUpdated()
533+
l.GetFullStatus().Version = l.GetSpec().Version
534+
}
535+
506536
if l.GetAddonsLayer().Generation != l.GetFullStatus().ObservedGeneration {
507537
l.SetUpdated()
508538
l.GetFullStatus().ObservedGeneration = l.GetAddonsLayer().Generation
@@ -565,7 +595,7 @@ func (r *AddonsLayerReconciler) repoMapperFunc(a handler.MapObject) []reconcile.
565595
layerList := []layers.Layer{}
566596
addons := []reconcile.Request{}
567597
for _, addon := range addonsList.Items {
568-
layer := layers.CreateLayer(r.Context, r.Client, r.k8client, r.Log, &addon) //nolint:scopelint // ok
598+
layer := layers.CreateLayer(r.Context, r.Client, r.k8client, r.Log, r.Recorder, r.Scheme, &addon) //nolint:scopelint // ok
569599
if layer.GetSpec().Source.Name == srcRepo.Name && layer.GetSpec().Source.NameSpace == srcRepo.Namespace {
570600
r.Log.V(1).Info("layer is using this source", append(logging.GetGitRepoInfo(srcRepo), append(logging.GetFunctionAndSource(logging.MyCaller), "layers", addons)...)...)
571601
layerList = append(layerList, layer)

go.sum

+3
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,10 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de
290290
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
291291
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
292292
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
293+
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
293294
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
294295
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
296+
github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo=
295297
github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
296298
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
297299
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
@@ -789,6 +791,7 @@ k8s.io/apimachinery v0.18.9/go.mod h1:PF5taHbXgTEJLU+xMypMmYTXTWPJ5LaW8bfsisxnEX
789791
k8s.io/apimachinery v0.19.2 h1:5Gy9vQpAGTKHPVOh5c4plE274X8D/6cuEiTO2zve7tc=
790792
k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
791793
k8s.io/apimachinery v0.19.3 h1:bpIQXlKjB4cB/oNpnNnV+BybGPR7iP5oYpsOTEJ4hgc=
794+
k8s.io/apimachinery v0.19.4 h1:+ZoddM7nbzrDCp0T3SWnyxqf8cbWPT2fkZImoyvHUG0=
792795
k8s.io/apiserver v0.18.6/go.mod h1:Zt2XvTHuaZjBz6EFYzpp+X4hTmgWGy8AthNVnTdm3Wg=
793796
k8s.io/apiserver v0.18.8/go.mod h1:12u5FuGql8Cc497ORNj79rhPdiXQC4bf53X/skR/1YM=
794797
k8s.io/apiserver v0.18.9/go.mod h1:vXQzMtUCLsGg1Bh+7Jo2mZKHpHZFCZn8eTNSepcIA1M=

pkg/layers/layers.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ import (
1616
"golang.org/x/mod/semver"
1717
corev1 "k8s.io/api/core/v1"
1818
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19+
"k8s.io/apimachinery/pkg/runtime"
1920
"k8s.io/apimachinery/pkg/types"
2021
"k8s.io/client-go/kubernetes"
22+
"k8s.io/client-go/tools/record"
23+
"k8s.io/client-go/tools/reference"
2124
"sigs.k8s.io/controller-runtime/pkg/client"
2225

2326
kraanv1alpha1 "github.com/fidelity/kraan/api/v1alpha1"
@@ -83,12 +86,15 @@ type KraanLayer struct {
8386
client client.Client
8487
k8client kubernetes.Interface
8588
log logr.Logger
89+
recorder record.EventRecorder
90+
ref *corev1.ObjectReference
8691
Layer `json:"-"`
8792
addonsLayer *kraanv1alpha1.AddonsLayer
8893
}
8994

9095
// CreateLayer creates a layer object.
91-
func CreateLayer(ctx context.Context, client client.Client, k8client kubernetes.Interface, log logr.Logger, addonsLayer *kraanv1alpha1.AddonsLayer) Layer {
96+
func CreateLayer(ctx context.Context, client client.Client, k8client kubernetes.Interface, log logr.Logger,
97+
recorder record.EventRecorder, scheme *runtime.Scheme, addonsLayer *kraanv1alpha1.AddonsLayer) Layer {
9298
l := &KraanLayer{
9399
requeue: false,
94100
delayed: false,
@@ -97,9 +103,14 @@ func CreateLayer(ctx context.Context, client client.Client, k8client kubernetes.
97103
log: log,
98104
client: client,
99105
k8client: k8client,
106+
recorder: recorder,
100107
addonsLayer: addonsLayer,
101108
}
102109
l.delay = l.addonsLayer.Spec.Interval.Duration
110+
var err error
111+
if l.ref, err = reference.GetReference(scheme, addonsLayer); err != nil {
112+
log.Error(err, "failed to get reference")
113+
}
103114
return l
104115
}
105116

@@ -166,17 +177,6 @@ func (l *KraanLayer) CheckK8sVersion() bool {
166177
return semver.Compare(versionInfo.String(), l.GetRequiredK8sVersion()) >= 0
167178
}
168179

169-
func (l *KraanLayer) trimConditions() {
170-
logging.TraceCall(l.GetLogger())
171-
defer logging.TraceExit(l.GetLogger())
172-
length := len(l.addonsLayer.Status.Conditions)
173-
if length < MaxConditions {
174-
return
175-
}
176-
trimedCond := l.addonsLayer.Status.Conditions[length-MaxConditions:]
177-
l.addonsLayer.Status.Conditions = trimedCond
178-
}
179-
180180
func (l *KraanLayer) setStatus(status, reason, message string) {
181181
logging.TraceCall(l.GetLogger())
182182
defer logging.TraceExit(l.GetLogger())
@@ -186,7 +186,7 @@ func (l *KraanLayer) setStatus(status, reason, message string) {
186186
if last.Reason == reason && last.Message == message && last.Type == status {
187187
return
188188
}
189-
last.Status = corev1.ConditionFalse
189+
l.addonsLayer.Status.Conditions = []kraanv1alpha1.Condition{}
190190
}
191191

192192
l.addonsLayer.Status.Conditions = append(l.addonsLayer.Status.Conditions, kraanv1alpha1.Condition{
@@ -197,14 +197,14 @@ func (l *KraanLayer) setStatus(status, reason, message string) {
197197
Reason: reason,
198198
Message: message,
199199
})
200-
l.trimConditions()
201200
l.addonsLayer.Status.State = status
202201
l.addonsLayer.Status.Version = l.addonsLayer.Spec.Version
203202
l.updated = true
204203
l.requeue = true
205204
if l.addonsLayer.Status.Resources == nil {
206205
l.addonsLayer.Status.Resources = []kraanv1alpha1.Resource{}
207206
}
207+
l.recorder.Event(l.ref, corev1.EventTypeNormal, reason, message)
208208
}
209209

210210
// SetStatusK8sVersion sets the addon layer's status to waiting for required K8s Version.

pkg/layers/layers_test.go

+14-72
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import (
1616
fakediscovery "k8s.io/client-go/discovery/fake"
1717
fakeK8s "k8s.io/client-go/kubernetes/fake"
1818
fakeTest "k8s.io/client-go/testing"
19+
"k8s.io/client-go/tools/record"
1920

2021
//k8sscheme "k8s.io/client-go/kubernetes/scheme"
22+
extv1b1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
2123
"sigs.k8s.io/controller-runtime/pkg/client/fake"
2224

2325
kraanv1alpha1 "github.com/fidelity/kraan/api/v1alpha1"
@@ -29,8 +31,17 @@ var (
2931
testScheme = runtime.NewScheme()
3032
// testCtx = context.Background()
3133
fakeK8sClient *fakeK8s.Clientset
34+
scheme = runtime.NewScheme()
3235
)
3336

37+
func init() {
38+
_ = corev1.AddToScheme(scheme) // nolint:errcheck // ok
39+
//_ = helmctlv2.AddToScheme(scheme) // nolint:errcheck // ok
40+
_ = kraanv1alpha1.AddToScheme(scheme) // nolint:errcheck // ok
41+
_ = sourcev1.AddToScheme(scheme) // nolint:errcheck // ok
42+
_ = extv1b1.AddToScheme(scheme) // nolint:errcheck // ok
43+
}
44+
3445
const (
3546
holdSet = "hold-set"
3647
k8sPending = "k8s-pending"
@@ -119,7 +130,8 @@ func getLayer(layerName, testDataFileName, reposDataFileName string) (layers.Lay
119130
if data == nil {
120131
return nil, fmt.Errorf("failed to find item: %s in test data", layerName)
121132
}
122-
return layers.CreateLayer(context.Background(), client, fakeK8sClient, logger, data), nil
133+
fakeRecorder := record.NewFakeRecorder(1000)
134+
return layers.CreateLayer(context.Background(), client, fakeK8sClient, logger, fakeRecorder, scheme, data), nil
123135
}
124136

125137
func testDelayedRequeue(t *testing.T, l layers.Layer) bool {
@@ -504,77 +516,7 @@ func TestHold(t *testing.T) {
504516
Reason: kraanv1alpha1.AddonsLayerK8sVersionReason,
505517
Message: kraanv1alpha1.AddonsLayerK8sVersionMsg},
506518
},
507-
}}, {
508-
name: "set status when maximum number of conditions already",
509-
layerName: maxConditions,
510-
status: kraanv1alpha1.PruningCondition,
511-
reason: kraanv1alpha1.AddonsLayerPruningReason,
512-
message: kraanv1alpha1.AddonsLayerPruningMsg,
513-
expected: &kraanv1alpha1.AddonsLayerStatus{
514-
State: kraanv1alpha1.PruningCondition,
515-
Version: versionOne,
516-
Conditions: []kraanv1alpha1.Condition{
517-
{
518-
Status: corev1.ConditionFalse,
519-
Version: versionOne,
520-
Type: kraanv1alpha1.PruningCondition,
521-
Reason: kraanv1alpha1.AddonsLayerPruningReason,
522-
Message: kraanv1alpha1.AddonsLayerPruningMsg},
523-
{
524-
Status: corev1.ConditionFalse,
525-
Version: versionOne,
526-
Type: kraanv1alpha1.ApplyPendingCondition,
527-
Reason: "waiting for layer: test-layer2, version: 0.1.01 to be applied.",
528-
Message: "Layer: test-layer2, current state: Applying."},
529-
{
530-
Status: corev1.ConditionFalse,
531-
Version: versionOne,
532-
Type: kraanv1alpha1.ApplyingCondition,
533-
Reason: kraanv1alpha1.AddonsLayerApplyingReason,
534-
Message: kraanv1alpha1.AddonsLayerApplyingMsg},
535-
{
536-
Status: corev1.ConditionFalse,
537-
Version: versionOne,
538-
Type: kraanv1alpha1.DeployedCondition,
539-
Reason: kraanv1alpha1.AddonsLayerDeployedReason,
540-
Message: ""},
541-
{
542-
Status: corev1.ConditionFalse,
543-
Version: versionOne,
544-
Type: kraanv1alpha1.K8sVersionCondition,
545-
Reason: kraanv1alpha1.AddonsLayerK8sVersionReason,
546-
Message: kraanv1alpha1.AddonsLayerK8sVersionMsg},
547-
{
548-
Status: corev1.ConditionFalse,
549-
Version: versionOne,
550-
Type: kraanv1alpha1.PruningCondition,
551-
Reason: kraanv1alpha1.AddonsLayerPruningReason,
552-
Message: kraanv1alpha1.AddonsLayerPruningMsg},
553-
{
554-
Status: corev1.ConditionFalse,
555-
Version: versionOne,
556-
Type: kraanv1alpha1.ApplyPendingCondition,
557-
Reason: "waiting for layer: test-layer2, version: 0.1.01 to be applied.",
558-
Message: "Layer: test-layer2, current state: Applying."},
559-
{
560-
Status: corev1.ConditionFalse,
561-
Version: versionOne,
562-
Type: kraanv1alpha1.ApplyingCondition,
563-
Reason: kraanv1alpha1.AddonsLayerApplyingReason,
564-
Message: kraanv1alpha1.AddonsLayerApplyingMsg},
565-
{
566-
Status: corev1.ConditionFalse,
567-
Version: versionOne,
568-
Type: kraanv1alpha1.DeployedCondition,
569-
Reason: kraanv1alpha1.AddonsLayerDeployedReason,
570-
Message: ""},
571-
{
572-
Status: corev1.ConditionTrue,
573-
Version: versionOne,
574-
Type: kraanv1alpha1.PruningCondition,
575-
Reason: kraanv1alpha1.AddonsLayerPruningReason,
576-
Message: kraanv1alpha1.AddonsLayerPruningMsg},
577-
}}}}
519+
}}}
578520
579521
for _, test := range tests {
580522
l, e := getLayer(test.layerName, layersData, reposData)

pkg/layers/testdata/layersdata.json

-71
Original file line numberDiff line numberDiff line change
@@ -133,77 +133,6 @@
133133
},
134134
"status": {
135135
"conditions": [
136-
{
137-
"type": "K8sVersion",
138-
"status": "False",
139-
"version": "0.1.01",
140-
"lastTransitionTime": null,
141-
"reason": "AddonsLayer is waiting for the required K8sVersion",
142-
"message": "The k8sVersion status means the manager has detected that the AddonsLayer needs a higher version of the Kubernetes API than the current version running on the cluster."
143-
},
144-
{
145-
"type": "Pruning",
146-
"status": "False",
147-
"version": "0.1.01",
148-
"lastTransitionTime": null,
149-
"reason": "AddonsLayer is being pruned",
150-
"message": "The pruning status means the manager is pruning objects removed from this layer"
151-
},
152-
{
153-
"lastTransitionTime": null,
154-
"message": "Layer: test-layer2, current state: Applying.",
155-
"reason": "waiting for layer: test-layer2, version: 0.1.01 to be applied.",
156-
"status": "False",
157-
"type": "ApplyPending",
158-
"version": "0.1.01"
159-
},
160-
{
161-
"lastTransitionTime": null,
162-
"message": "The applying status means the manager is either applying the yaml files or waiting for the HelmReleases to successfully deploy.",
163-
"reason": "AddonsLayer is being applied",
164-
"status": "False",
165-
"type": "Applying",
166-
"version": "0.1.01"
167-
},
168-
{
169-
"lastTransitionTime": null,
170-
"reason": "AddonsLayer is Deployed",
171-
"status": "False",
172-
"type": "Deployed",
173-
"version": "0.1.01"
174-
},
175-
{
176-
"type": "K8sVersion",
177-
"status": "False",
178-
"version": "0.1.01",
179-
"lastTransitionTime": null,
180-
"reason": "AddonsLayer is waiting for the required K8sVersion",
181-
"message": "The k8sVersion status means the manager has detected that the AddonsLayer needs a higher version of the Kubernetes API than the current version running on the cluster."
182-
},
183-
{
184-
"type": "Pruning",
185-
"status": "False",
186-
"version": "0.1.01",
187-
"lastTransitionTime": null,
188-
"reason": "AddonsLayer is being pruned",
189-
"message": "The pruning status means the manager is pruning objects removed from this layer"
190-
},
191-
{
192-
"lastTransitionTime": null,
193-
"message": "Layer: test-layer2, current state: Applying.",
194-
"reason": "waiting for layer: test-layer2, version: 0.1.01 to be applied.",
195-
"status": "False",
196-
"type": "ApplyPending",
197-
"version": "0.1.01"
198-
},
199-
{
200-
"lastTransitionTime": null,
201-
"message": "The applying status means the manager is either applying the yaml files or waiting for the HelmReleases to successfully deploy.",
202-
"reason": "AddonsLayer is being applied",
203-
"status": "False",
204-
"type": "Applying",
205-
"version": "0.1.01"
206-
},
207136
{
208137
"lastTransitionTime": null,
209138
"reason": "AddonsLayer is Deployed",

0 commit comments

Comments
 (0)