Skip to content

Commit

Permalink
Implement event recording
Browse files Browse the repository at this point in the history
- emit Kubernetes events when a release status changes
- forward events to notification controller
  • Loading branch information
stefanprodan committed Jul 9, 2020
1 parent f77e034 commit b94dcca
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 12 deletions.
11 changes: 11 additions & 0 deletions api/v2alpha1/helmrelease_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,17 @@ func ShouldUninstall(hr HelmRelease, releaseRevision int) bool {
return false
}

// HelmReleaseReadyMessage returns the message of the HelmRelease
// of type Ready with status true if present, or an empty string.
func HelmReleaseReadyMessage(hr HelmRelease) string {
for _, condition := range hr.Status.Conditions {
if condition.Type == ReadyCondition && condition.Status == corev1.ConditionTrue {
return condition.Message
}
}
return ""
}

const (
// ReconcileAtAnnotation is the annotation used for triggering a
// reconciliation outside of the defined schedule.
Expand Down
43 changes: 39 additions & 4 deletions controllers/helmrelease_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest"
kuberecorder "k8s.io/client-go/tools/record"
"k8s.io/client-go/tools/reference"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"

"github.com/fluxcd/pkg/lockedfile"
"github.com/fluxcd/pkg/recorder"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"

v2 "github.com/fluxcd/helm-controller/api/v2alpha1"
Expand All @@ -53,10 +56,12 @@ import (
// HelmReleaseReconciler reconciles a HelmRelease object
type HelmReleaseReconciler struct {
client.Client
Config *rest.Config
Log logr.Logger
Scheme *runtime.Scheme
requeueDependency time.Duration
Config *rest.Config
Log logr.Logger
Scheme *runtime.Scheme
requeueDependency time.Duration
EventRecorder kuberecorder.EventRecorder
ExternalEventRecorder *recorder.EventRecorder
}

// +kubebuilder:rbac:groups=helm.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -123,6 +128,7 @@ func (r *HelmReleaseReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error)
// instead we requeue on a fixed interval.
msg := fmt.Sprintf("Dependencies do not meet ready condition (%s), retrying in %s", err.Error(), r.requeueDependency.String())
log.Info(msg)
r.event(hr, source.GetArtifact().Revision, recorder.EventSeverityInfo, msg)
return ctrl.Result{RequeueAfter: r.requeueDependency}, nil
}
log.Info("All dependencies area ready, proceeding with release")
Expand All @@ -131,6 +137,9 @@ func (r *HelmReleaseReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error)
reconciledHr, err := r.release(log, hr, source)
if err != nil {
log.Error(err, "HelmRelease reconciliation failed", "revision", source.GetArtifact().Revision)
r.event(hr, source.GetArtifact().Revision, recorder.EventSeverityError, err.Error())
} else {
r.event(hr, source.GetArtifact().Revision, recorder.EventSeverityInfo, v2.HelmReleaseReadyMessage(reconciledHr))
}

if err := r.Status().Update(ctx, &reconciledHr); err != nil {
Expand Down Expand Up @@ -285,6 +294,32 @@ func (r *HelmReleaseReconciler) checkDependencies(hr v2.HelmRelease) error {
return nil
}

func (r *HelmReleaseReconciler) event(hr v2.HelmRelease, revision, severity, msg string) {
r.EventRecorder.Event(&hr, "Normal", severity, msg)
objRef, err := reference.GetReference(r.Scheme, &hr)
if err != nil {
r.Log.WithValues(
strings.ToLower(hr.Kind),
fmt.Sprintf("%s/%s", hr.GetNamespace(), hr.GetName()),
).Error(err, "unable to send event")
return
}

if r.ExternalEventRecorder != nil {
var meta map[string]string
if revision != "" {
meta = map[string]string{"revision": revision}
}
if err := r.ExternalEventRecorder.Eventf(*objRef, meta, severity, severity, msg); err != nil {
r.Log.WithValues(
strings.ToLower(hr.Kind),
fmt.Sprintf("%s/%s", hr.GetNamespace(), hr.GetName()),
).Error(err, "unable to send event")
return
}
}
}

func install(cfg *action.Configuration, chart *chart.Chart, hr v2.HelmRelease) (*release.Release, error) {
install := action.NewInstall(cfg)
install.ReleaseName = hr.GetReleaseName()
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,14 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
Expand Down
32 changes: 24 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ import (
"os"
"time"

sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"

helmv2alpha1 "github.com/fluxcd/helm-controller/api/v2alpha1"
"github.com/fluxcd/helm-controller/controllers"
"github.com/fluxcd/pkg/recorder"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"

v2 "github.com/fluxcd/helm-controller/api/v2alpha1"
// +kubebuilder:scaffold:imports
)

Expand All @@ -42,20 +44,22 @@ func init() {
_ = clientgoscheme.AddToScheme(scheme)

_ = sourcev1.AddToScheme(scheme)
_ = helmv2alpha1.AddToScheme(scheme)
_ = v2.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
}

func main() {
var (
metricsAddr string
eventsAddr string
enableLeaderElection bool
concurrent int
requeueDependency time.Duration
logJSON bool
)

flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&eventsAddr, "events-addr", "", "The address of the events receiver.")
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
Expand All @@ -66,6 +70,16 @@ func main() {

ctrl.SetLogger(zap.New(zap.UseDevMode(!logJSON)))

var eventRecorder *recorder.EventRecorder
if eventsAddr != "" {
if er, err := recorder.NewEventRecorder(eventsAddr, "kustomize-controller"); err != nil {
setupLog.Error(err, "unable to create event recorder")
os.Exit(1)
} else {
eventRecorder = er
}
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
Expand All @@ -87,15 +101,17 @@ func main() {
os.Exit(1)
}
if err = (&controllers.HelmReleaseReconciler{
Client: mgr.GetClient(),
Config: mgr.GetConfig(),
Log: ctrl.Log.WithName("controllers").WithName(helmv2alpha1.HelmReleaseKind),
Scheme: mgr.GetScheme(),
Client: mgr.GetClient(),
Config: mgr.GetConfig(),
Log: ctrl.Log.WithName("controllers").WithName(v2.HelmReleaseKind),
Scheme: mgr.GetScheme(),
EventRecorder: mgr.GetEventRecorderFor("helm-controller"),
ExternalEventRecorder: eventRecorder,
}).SetupWithManager(mgr, controllers.HelmReleaseReconcilerOptions{
MaxConcurrentReconciles: concurrent,
DependencyRequeueInterval: requeueDependency,
}); err != nil {
setupLog.Error(err, "unable to create controller", "controller", helmv2alpha1.HelmReleaseKind)
setupLog.Error(err, "unable to create controller", "controller", v2.HelmReleaseKind)
os.Exit(1)
}
// +kubebuilder:scaffold:builder
Expand Down

0 comments on commit b94dcca

Please sign in to comment.