Skip to content
This repository was archived by the owner on Jan 25, 2019. It is now read-only.

Commit 535b588

Browse files
authored
Merge pull request #48 from joelanford/multiple-resources
Support multiple resources
2 parents 0a420ad + deb80f7 commit 535b588

File tree

5 files changed

+218
-58
lines changed

5 files changed

+218
-58
lines changed

helm-app-operator/Gopkg.lock

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

helm-app-operator/cmd/manager/main.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,20 @@ func main() {
5555
logrus.Fatal(err)
5656
}
5757

58-
// Dynamically load the helm installer based on the environment
59-
gvk, installer, err := helm.NewInstallerFromEnv(storageBackend, tillerKubeClient)
58+
installers, err := helm.NewInstallersFromEnv(storageBackend, tillerKubeClient)
6059
if err != nil {
6160
logrus.Fatal(err)
6261
}
6362

64-
// Register the controller with the manager.
65-
controller.Add(mgr, controller.WatchOptions{
66-
Namespace: namespace,
67-
GVK: gvk,
68-
Installer: installer,
69-
ResyncPeriod: 5 * time.Second,
70-
})
63+
for gvk, installer := range installers {
64+
// Register the controller with the manager.
65+
controller.Add(mgr, controller.WatchOptions{
66+
Namespace: namespace,
67+
GVK: gvk,
68+
Installer: installer,
69+
ResyncPeriod: 5 * time.Second,
70+
})
71+
}
7172

7273
logrus.Print("Starting the Cmd.")
7374

helm-app-operator/pkg/helm/controller/controller.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ import (
77

88
"github.com/sirupsen/logrus"
99
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1011
"k8s.io/apimachinery/pkg/runtime/schema"
12+
"k8s.io/apimachinery/pkg/types"
1113
"sigs.k8s.io/controller-runtime/pkg/controller"
1214
crthandler "sigs.k8s.io/controller-runtime/pkg/handler"
1315
"sigs.k8s.io/controller-runtime/pkg/manager"
1416
"sigs.k8s.io/controller-runtime/pkg/source"
1517

16-
appv1alpha1 "github.com/operator-framework/helm-app-operator-kit/helm-app-operator/pkg/apis/app/v1alpha1"
1718
"github.com/operator-framework/helm-app-operator-kit/helm-app-operator/pkg/helm"
1819
)
1920

@@ -32,15 +33,15 @@ func Add(mgr manager.Manager, options WatchOptions) {
3233
options.ResyncPeriod = time.Minute
3334
}
3435
r := &helmOperatorReconciler{
35-
Client: mgr.GetClient(),
36-
GVK: options.GVK,
37-
Installer: options.Installer,
38-
ResyncPeriod: options.ResyncPeriod,
36+
Client: mgr.GetClient(),
37+
GVK: options.GVK,
38+
Installer: options.Installer,
39+
ResyncPeriod: options.ResyncPeriod,
40+
lastResourceVersions: map[types.NamespacedName]string{},
3941
}
4042

4143
// Register the GVK with the schema
42-
mgr.GetScheme().AddKnownTypeWithName(options.GVK, &appv1alpha1.HelmApp{})
43-
mgr.GetScheme().AddKnownTypeWithName(options.GVK.GroupVersion().WithKind(options.GVK.Kind+"List"), &appv1alpha1.HelmAppList{})
44+
mgr.GetScheme().AddKnownTypeWithName(options.GVK, &unstructured.Unstructured{})
4445
metav1.AddToGroupVersion(mgr.GetScheme(), options.GVK.GroupVersion())
4546

4647
controllerName := fmt.Sprintf("%v-controller", strings.ToLower(options.GVK.Kind))
@@ -49,7 +50,8 @@ func Add(mgr manager.Manager, options WatchOptions) {
4950
logrus.Fatal(err)
5051
}
5152

52-
o := &appv1alpha1.HelmApp{}
53+
o := &unstructured.Unstructured{}
54+
o.SetGroupVersionKind(options.GVK)
5355
if err := c.Watch(&source.Kind{Type: o}, &crthandler.EnqueueRequestForObject{}); err != nil {
5456
logrus.Fatal(err)
5557
}

helm-app-operator/pkg/helm/controller/reconcile.go

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@ package controller
33
import (
44
"context"
55
"fmt"
6+
"sync"
67
"time"
78

89
"github.com/sirupsen/logrus"
910

1011
apierrors "k8s.io/apimachinery/pkg/api/errors"
12+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1113
"k8s.io/apimachinery/pkg/runtime/schema"
14+
"k8s.io/apimachinery/pkg/types"
1215
"sigs.k8s.io/controller-runtime/pkg/client"
1316
"sigs.k8s.io/controller-runtime/pkg/reconcile"
1417

15-
appv1alpha1 "github.com/operator-framework/helm-app-operator-kit/helm-app-operator/pkg/apis/app/v1alpha1"
1618
"github.com/operator-framework/helm-app-operator-kit/helm-app-operator/pkg/helm"
1719
)
1820

@@ -21,26 +23,61 @@ type helmOperatorReconciler struct {
2123
GVK schema.GroupVersionKind
2224
Installer helm.Installer
2325
ResyncPeriod time.Duration
26+
27+
lastResourceVersions map[types.NamespacedName]string
28+
mutex sync.RWMutex
2429
}
2530

26-
var lastResourceVersion string
31+
const (
32+
finalizer = "uninstall-helm-release"
33+
)
2734

28-
func (r helmOperatorReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) {
35+
func (r *helmOperatorReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) {
2936
logrus.Infof("processing %s", request.NamespacedName)
3037

31-
o := &appv1alpha1.HelmApp{}
32-
err := r.Client.Get(context.TODO(), request.NamespacedName, o)
38+
o := &unstructured.Unstructured{}
3339
o.SetGroupVersionKind(r.GVK)
34-
o.SetNamespace(request.Namespace)
35-
o.SetName(request.Name)
40+
err := r.Client.Get(context.TODO(), request.NamespacedName, o)
41+
if apierrors.IsNotFound(err) {
42+
return reconcile.Result{}, nil
43+
}
3644
if err != nil {
37-
if apierrors.IsNotFound(err) {
38-
_, err = r.Installer.UninstallRelease(o)
45+
return reconcile.Result{}, err
46+
}
47+
48+
deleted := o.GetDeletionTimestamp() != nil
49+
pendingFinalizers := o.GetFinalizers()
50+
if !deleted && !contains(pendingFinalizers, finalizer) {
51+
logrus.Debugf("adding finalizer %s to resource", finalizer)
52+
finalizers := append(pendingFinalizers, finalizer)
53+
o.SetFinalizers(finalizers)
54+
err := r.Client.Update(context.TODO(), o)
55+
return reconcile.Result{}, err
56+
}
57+
if deleted {
58+
if !contains(pendingFinalizers, finalizer) {
59+
logrus.Info("resouce is terminated, skipping reconciliation")
60+
return reconcile.Result{}, nil
61+
}
62+
63+
_, err = r.Installer.UninstallRelease(o)
64+
if err != nil {
65+
return reconcile.Result{}, err
66+
}
67+
68+
finalizers := []string{}
69+
for _, pendingFinalizer := range pendingFinalizers {
70+
if pendingFinalizer != finalizer {
71+
finalizers = append(finalizers, pendingFinalizer)
72+
}
3973
}
74+
o.SetFinalizers(finalizers)
75+
err := r.Client.Update(context.TODO(), o)
4076
return reconcile.Result{}, err
4177
}
4278

43-
if o.GetResourceVersion() == lastResourceVersion {
79+
lastResourceVersion, ok := r.getLastResourceVersion(request.NamespacedName)
80+
if ok && o.GetResourceVersion() == lastResourceVersion {
4481
logrus.Infof("skipping %s because resource version has not changed", request.NamespacedName)
4582
return reconcile.Result{RequeueAfter: r.ResyncPeriod}, nil
4683
}
@@ -56,7 +93,29 @@ func (r helmOperatorReconciler) Reconcile(request reconcile.Request) (reconcile.
5693
logrus.Errorf(err.Error())
5794
return reconcile.Result{}, fmt.Errorf("failed to update custom resource status: %v", err)
5895
}
59-
lastResourceVersion = o.GetResourceVersion()
96+
r.setLastResourceVersion(request.NamespacedName, o.GetResourceVersion())
6097

6198
return reconcile.Result{RequeueAfter: r.ResyncPeriod}, nil
6299
}
100+
101+
func contains(l []string, s string) bool {
102+
for _, elem := range l {
103+
if elem == s {
104+
return true
105+
}
106+
}
107+
return false
108+
}
109+
110+
func (r *helmOperatorReconciler) getLastResourceVersion(n types.NamespacedName) (string, bool) {
111+
r.mutex.RLock()
112+
defer r.mutex.RUnlock()
113+
v, ok := r.lastResourceVersions[n]
114+
return v, ok
115+
}
116+
117+
func (r *helmOperatorReconciler) setLastResourceVersion(n types.NamespacedName, v string) {
118+
r.mutex.Lock()
119+
defer r.mutex.Unlock()
120+
r.lastResourceVersions[n] = v
121+
}

0 commit comments

Comments
 (0)