Skip to content

Commit e838f7f

Browse files
authored
Merge pull request #530 from alecmerdler/ALM-378
Emit Kubernetes Events for ClusterServiceVersion
2 parents 4b28e17 + d6417a8 commit e838f7f

File tree

20 files changed

+3806
-278
lines changed

20 files changed

+3806
-278
lines changed

Gopkg.lock

Lines changed: 37 additions & 267 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/api/apis/operators/v1alpha1/clusterserviceversion.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package v1alpha1
22

33
import (
4+
"k8s.io/api/core/v1"
45
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6+
"k8s.io/client-go/tools/record"
57
)
68

79
// obsoleteReasons are the set of reasons that mean a CSV should no longer be processed as active
@@ -10,6 +12,17 @@ var obsoleteReasons = map[ConditionReason]struct{}{
1012
CSVReasonBeingReplaced: {},
1113
}
1214

15+
func (c *ClusterServiceVersion) SetPhaseWithEvent(phase ClusterServiceVersionPhase, reason ConditionReason, message string, recorder record.EventRecorder) {
16+
var eventtype string
17+
if phase == CSVPhaseFailed {
18+
eventtype = v1.EventTypeWarning
19+
} else {
20+
eventtype = v1.EventTypeNormal
21+
}
22+
go recorder.Event(c, eventtype, string(reason), message)
23+
c.SetPhase(phase, reason, message)
24+
}
25+
1326
// SetPhase sets the current phase and adds a condition if necessary
1427
func (c *ClusterServiceVersion) SetPhase(phase ClusterServiceVersionPhase, reason ConditionReason, message string) {
1528
c.Status.LastUpdateTime = metav1.Now()

pkg/controller/operators/olm/operator.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"time"
77

8+
"k8s.io/client-go/tools/record"
9+
810
log "github.com/sirupsen/logrus"
911
"k8s.io/api/apps/v1"
1012
corev1 "k8s.io/api/core/v1"
@@ -21,6 +23,7 @@ import (
2123
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions"
2224
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/annotator"
2325
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
26+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/event"
2427
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
2528
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
2629
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
@@ -44,6 +47,7 @@ type Operator struct {
4447
clusterRoleLister crbacv1.ClusterRoleLister
4548
clusterRoleBindingLister crbacv1.ClusterRoleBindingLister
4649
annotator *annotator.Annotator
50+
recorder record.EventRecorder
4751
cleanupFunc func()
4852
}
4953

@@ -60,12 +64,17 @@ func NewOperator(crClient versioned.Interface, opClient operatorclient.ClientInt
6064
return nil, err
6165
}
6266
namespaceAnnotator := annotator.NewAnnotator(queueOperator.OpClient, annotations)
67+
eventRecorder, err := event.NewRecorder(opClient.KubernetesInterface().CoreV1().Events(metav1.NamespaceAll))
68+
if err != nil {
69+
return nil, err
70+
}
6371

6472
op := &Operator{
6573
Operator: queueOperator,
6674
client: crClient,
6775
resolver: resolver,
6876
annotator: namespaceAnnotator,
77+
recorder: eventRecorder,
6978
cleanupFunc: func() {
7079
namespaceAnnotator.CleanNamespaceAnnotations(namespaces)
7180
},
@@ -281,8 +290,7 @@ func (a *Operator) syncClusterServiceVersion(obj interface{}) (syncError error)
281290
return
282291
}
283292

284-
// transitionCSVState moves the CSV status state machine along based on the current value and the current cluster
285-
// state.
293+
// transitionCSVState moves the CSV status state machine along based on the current value and the current cluster state.
286294
func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v1alpha1.ClusterServiceVersion, syncError error) {
287295
logger := log.WithFields(log.Fields{
288296
"csv": in.GetName(),
@@ -301,31 +309,31 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
301309
switch out.Status.Phase {
302310
case v1alpha1.CSVPhaseNone:
303311
logger.Infof("scheduling ClusterServiceVersion for requirement verification")
304-
out.SetPhase(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsUnknown, "requirements not yet checked")
312+
out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsUnknown, "requirements not yet checked", a.recorder)
305313
case v1alpha1.CSVPhasePending:
306314
met, statuses, err := a.requirementAndPermissionStatus(out)
307315
if err != nil {
308316
logger.Info("invalid install strategy")
309-
out.SetPhase(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidStrategy, fmt.Sprintf("install strategy invalid: %s", err.Error()))
317+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidStrategy, fmt.Sprintf("install strategy invalid: %s", err.Error()), a.recorder)
310318
return
311319
}
312320
out.SetRequirementStatus(statuses)
313321

314322
if !met {
315323
logger.Info("requirements were not met")
316-
out.SetPhase(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsNotMet, "one or more requirements couldn't be found")
324+
out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonRequirementsNotMet, "one or more requirements couldn't be found", a.recorder)
317325
syncError = ErrRequirementsNotMet
318326
return
319327
}
320328

321329
// check for CRD ownership conflicts
322330
if syncError = a.crdOwnerConflicts(out, a.csvsInNamespace(out.GetNamespace())); syncError != nil {
323-
out.SetPhase(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonOwnerConflict, fmt.Sprintf("owner conflict: %s", syncError))
331+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonOwnerConflict, fmt.Sprintf("owner conflict: %s", syncError), a.recorder)
324332
return
325333
}
326334

327335
logger.Info("scheduling ClusterServiceVersion for install")
328-
out.SetPhase(v1alpha1.CSVPhaseInstallReady, v1alpha1.CSVReasonRequirementsMet, "all requirements found, attempting install")
336+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseInstallReady, v1alpha1.CSVReasonRequirementsMet, "all requirements found, attempting install", a.recorder)
329337
case v1alpha1.CSVPhaseInstallReady:
330338

331339
installer, strategy, _ := a.parseStrategiesAndUpdateStatus(out)
@@ -337,16 +345,16 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
337345
// Install owned APIServices and update strategy with serving cert data
338346
strategy, syncError = a.installOwnedAPIServiceRequirements(out, strategy)
339347
if syncError != nil {
340-
out.SetPhase(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentFailed, fmt.Sprintf("install API services failed: %s", syncError))
348+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentFailed, fmt.Sprintf("install API services failed: %s", syncError), a.recorder)
341349
return
342350
}
343351

344352
if syncError = installer.Install(strategy); syncError != nil {
345-
out.SetPhase(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentFailed, fmt.Sprintf("install strategy failed: %s", syncError))
353+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentFailed, fmt.Sprintf("install strategy failed: %s", syncError), a.recorder)
346354
return
347355
}
348356

349-
out.SetPhase(v1alpha1.CSVPhaseInstalling, v1alpha1.CSVReasonInstallSuccessful, "waiting for install components to report healthy")
357+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseInstalling, v1alpha1.CSVReasonInstallSuccessful, "waiting for install components to report healthy", a.recorder)
350358
a.requeueCSV(out.GetName(), out.GetNamespace())
351359
return
352360
case v1alpha1.CSVPhaseInstalling:
@@ -382,7 +390,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
382390
// if we can find a newer version that's successfully installed, we're safe to mark all intermediates
383391
for _, csv := range a.findIntermediatesForDeletion(out) {
384392
// we only mark them in this step, in case some get deleted but others fail and break the replacement chain
385-
csv.SetPhase(v1alpha1.CSVPhaseDeleting, v1alpha1.CSVReasonReplaced, "has been replaced by a newer ClusterServiceVersion that has successfully installed.")
393+
csv.SetPhaseWithEvent(v1alpha1.CSVPhaseDeleting, v1alpha1.CSVReasonReplaced, "has been replaced by a newer ClusterServiceVersion that has successfully installed.", a.recorder)
386394
// ignore errors and success here; this step is just an optimization to speed up GC
387395
a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).UpdateStatus(csv)
388396
a.requeueCSV(csv.GetName(), csv.GetNamespace())

pkg/lib/event/event.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package event
2+
3+
import (
4+
"github.com/golang/glog"
5+
"k8s.io/api/core/v1"
6+
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
7+
"k8s.io/client-go/tools/record"
8+
9+
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/scheme"
10+
)
11+
12+
const component string = "operator-lifecycle-manager"
13+
14+
// NewRecorder returns an EventRecorder type that can be
15+
// used to post Events to different object's lifecycles.
16+
func NewRecorder(event typedcorev1.EventInterface) (record.EventRecorder, error) {
17+
eventBroadcaster := record.NewBroadcaster()
18+
eventBroadcaster.StartLogging(glog.Infof)
19+
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: event})
20+
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: component})
21+
22+
return recorder, nil
23+
}

pkg/metrics/metrics.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
77
)
88

9+
// TODO(alecmerdler): Can we use this to emit Kubernetes events?
910
type MetricsProvider interface {
1011
HandleMetrics() error
1112
}

vendor/github.com/golang/groupcache/LICENSE

Lines changed: 191 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)