Browse Source

Merge pull request #1906 from weaveworks/helm/refactor-hr-sync

Make all Helm releases through the operator
Hidde Beydals 6 months ago
parent
commit
ff93ae039b
No account linked to committer's email address

+ 2
- 0
chart/flux/templates/helm-operator-crd.yaml View File

@@ -21,6 +21,8 @@ spec:
21 21
     shortNames:
22 22
     - hr
23 23
   scope: Namespaced
24
+  subresources:
25
+    status: {}
24 26
   version: v1beta1
25 27
   versions:
26 28
     - name: v1beta1

+ 15
- 14
cmd/helm-operator/main.go View File

@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/spf13/pflag"
14 14
 	"k8s.io/client-go/kubernetes"
15 15
 	"k8s.io/client-go/tools/clientcmd"
16
+	"k8s.io/client-go/util/workqueue"
16 17
 
17 18
 	"github.com/weaveworks/flux/checkpoint"
18 19
 	clientset "github.com/weaveworks/flux/integrations/client/clientset/versioned"
@@ -136,19 +137,19 @@ func main() {
136 137
 
137 138
 	cfg, err := clientcmd.BuildConfigFromFlags(*master, *kubeconfig)
138 139
 	if err != nil {
139
-		mainLogger.Log("error", fmt.Sprintf("Error building kubeconfig: %v", err))
140
+		mainLogger.Log("error", fmt.Sprintf("error building kubeconfig: %v", err))
140 141
 		os.Exit(1)
141 142
 	}
142 143
 
143 144
 	kubeClient, err := kubernetes.NewForConfig(cfg)
144 145
 	if err != nil {
145
-		mainLogger.Log("error", fmt.Sprintf("Error building kubernetes clientset: %v", err))
146
+		mainLogger.Log("error", fmt.Sprintf("error building kubernetes clientset: %v", err))
146 147
 		os.Exit(1)
147 148
 	}
148 149
 
149 150
 	ifClient, err := clientset.NewForConfig(cfg)
150 151
 	if err != nil {
151
-		mainLogger.Log("error", fmt.Sprintf("Error building integrations clientset: %v", err))
152
+		mainLogger.Log("error", fmt.Sprintf("error building integrations clientset: %v", err))
152 153
 		os.Exit(1)
153 154
 	}
154 155
 
@@ -169,27 +170,27 @@ func main() {
169 170
 	statusUpdater := status.New(ifClient, kubeClient, helmClient, *namespace)
170 171
 	go statusUpdater.Loop(shutdown, log.With(logger, "component", "annotator"))
171 172
 
172
-	// release instance is needed during the sync of Charts changes and during the sync of HelmRelease changes
173
+	nsOpt := ifinformers.WithNamespace(*namespace)
174
+	ifInformerFactory := ifinformers.NewSharedInformerFactoryWithOptions(ifClient, *chartsSyncInterval, nsOpt)
175
+	fhrInformer := ifInformerFactory.Flux().V1beta1().HelmReleases()
176
+	go ifInformerFactory.Start(shutdown)
177
+
178
+	queue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "ChartRelease")
179
+
180
+	// release instance is needed during the sync of git chart changes and during the sync of HelmRelease changes
173 181
 	rel := release.New(log.With(logger, "component", "release"), helmClient)
174 182
 	chartSync := chartsync.New(
175 183
 		log.With(logger, "component", "chartsync"),
176
-		chartsync.Polling{Interval: *chartsSyncInterval},
177
-		chartsync.Clients{KubeClient: *kubeClient, IfClient: *ifClient},
184
+		chartsync.Clients{KubeClient: *kubeClient, IfClient: *ifClient, FhrLister: fhrInformer.Lister()},
178 185
 		rel,
186
+		queue,
179 187
 		chartsync.Config{LogDiffs: *logReleaseDiffs, UpdateDeps: *updateDependencies, GitTimeout: *gitTimeout, GitPollInterval: *gitPollInterval},
180 188
 		*namespace,
181
-		statusUpdater,
182 189
 	)
183 190
 	chartSync.Run(shutdown, errc, shutdownWg)
184 191
 
185
-	nsOpt := ifinformers.WithNamespace(*namespace)
186
-	ifInformerFactory := ifinformers.NewSharedInformerFactoryWithOptions(ifClient, 30*time.Second, nsOpt)
187
-	fhrInformer := ifInformerFactory.Flux().V1beta1().HelmReleases()
188
-
189 192
 	// start FluxRelease informer
190
-	opr := operator.New(log.With(logger, "component", "operator"), *logReleaseDiffs, kubeClient, fhrInformer, chartSync)
191
-	go ifInformerFactory.Start(shutdown)
192
-
193
+	opr := operator.New(log.With(logger, "component", "operator"), *logReleaseDiffs, kubeClient, fhrInformer, queue, chartSync)
193 194
 	checkpoint.CheckForUpdates(product, version, nil, log.With(logger, "component", "checkpoint"))
194 195
 
195 196
 	// start HTTP server

+ 2
- 0
deploy-helm/flux-helm-release-crd.yaml View File

@@ -12,6 +12,8 @@ spec:
12 12
     shortNames:
13 13
     - hr
14 14
   scope: Namespaced
15
+  subresources:
16
+    status: {}
15 17
   version: v1beta1
16 18
   versions:
17 19
     - name: v1beta1

+ 0
- 1
integrations/apis/flux.weave.works/v1beta1/types.go View File

@@ -12,7 +12,6 @@ import (
12 12
 )
13 13
 
14 14
 // +genclient
15
-// +genclient:noStatus
16 15
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
17 16
 
18 17
 // FluxHelmRelease represents custom resource associated with a Helm Chart

+ 12
- 0
integrations/client/clientset/versioned/typed/flux.weave.works/v1beta1/fake/fake_helmrelease.go View File

@@ -100,6 +100,18 @@ func (c *FakeHelmReleases) Update(helmRelease *v1beta1.HelmRelease) (result *v1b
100 100
 	return obj.(*v1beta1.HelmRelease), err
101 101
 }
102 102
 
103
+// UpdateStatus was generated because the type contains a Status member.
104
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
105
+func (c *FakeHelmReleases) UpdateStatus(helmRelease *v1beta1.HelmRelease) (*v1beta1.HelmRelease, error) {
106
+	obj, err := c.Fake.
107
+		Invokes(testing.NewUpdateSubresourceAction(helmreleasesResource, "status", c.ns, helmRelease), &v1beta1.HelmRelease{})
108
+
109
+	if obj == nil {
110
+		return nil, err
111
+	}
112
+	return obj.(*v1beta1.HelmRelease), err
113
+}
114
+
103 115
 // Delete takes name of the helmRelease and deletes it. Returns an error if one occurs.
104 116
 func (c *FakeHelmReleases) Delete(name string, options *v1.DeleteOptions) error {
105 117
 	_, err := c.Fake.

+ 17
- 0
integrations/client/clientset/versioned/typed/flux.weave.works/v1beta1/helmrelease.go View File

@@ -39,6 +39,7 @@ type HelmReleasesGetter interface {
39 39
 type HelmReleaseInterface interface {
40 40
 	Create(*v1beta1.HelmRelease) (*v1beta1.HelmRelease, error)
41 41
 	Update(*v1beta1.HelmRelease) (*v1beta1.HelmRelease, error)
42
+	UpdateStatus(*v1beta1.HelmRelease) (*v1beta1.HelmRelease, error)
42 43
 	Delete(name string, options *v1.DeleteOptions) error
43 44
 	DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
44 45
 	Get(name string, options v1.GetOptions) (*v1beta1.HelmRelease, error)
@@ -132,6 +133,22 @@ func (c *helmReleases) Update(helmRelease *v1beta1.HelmRelease) (result *v1beta1
132 133
 	return
133 134
 }
134 135
 
136
+// UpdateStatus was generated because the type contains a Status member.
137
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
138
+
139
+func (c *helmReleases) UpdateStatus(helmRelease *v1beta1.HelmRelease) (result *v1beta1.HelmRelease, err error) {
140
+	result = &v1beta1.HelmRelease{}
141
+	err = c.client.Put().
142
+		Namespace(c.ns).
143
+		Resource("helmreleases").
144
+		Name(helmRelease.Name).
145
+		SubResource("status").
146
+		Body(helmRelease).
147
+		Do().
148
+		Into(result)
149
+	return
150
+}
151
+
135 152
 // Delete takes name of the helmRelease and deletes it. Returns an error if one occurs.
136 153
 func (c *helmReleases) Delete(name string, options *v1.DeleteOptions) error {
137 154
 	return c.client.Delete().

+ 143
- 162
integrations/helm/chartsync/chartsync.go View File

@@ -8,19 +8,17 @@ reconciled:
8 8
 
9 9
  1a. There is a HelmRelease resource, but no corresponding
10 10
    release. This can happen when the helm operator is first run, for
11
-   example. The ChartChangeSync periodically checks for this by
12
-   running through the resources and installing any that aren't
13
-   released already.
11
+   example.
14 12
 
15 13
  1b. The release corresponding to a HelmRelease has been updated by
16 14
    some other means, perhaps while the operator wasn't running. This
17
-   is also checked periodically, by doing a dry-run release and
18
-   comparing the result to the release.
15
+   is also checked, by doing a dry-run release and comparing the result
16
+   to the release.
19 17
 
20 18
  2. The chart has changed in git, meaning the release is out of
21
-   date. The ChartChangeSync responds to new git commits by looking at
22
-   each chart that's referenced by a HelmRelease, and if it's
23
-   changed since the last seen commit, updating the release.
19
+   date. The ChartChangeSync responds to new git commits by looking up
20
+   each chart that makes use of the mirror that has new commits,
21
+   replacing the clone for that chart, and scheduling a new release.
24 22
 
25 23
 1a.) and 1b.) run on the same schedule, and 2.) is run when a git
26 24
 mirror reports it has fetched from upstream _and_ (upon checking) the
@@ -44,6 +42,8 @@ import (
44 42
 	"sync"
45 43
 	"time"
46 44
 
45
+	"k8s.io/apimachinery/pkg/labels"
46
+
47 47
 	"github.com/go-kit/kit/log"
48 48
 	google_protobuf "github.com/golang/protobuf/ptypes/any"
49 49
 	"github.com/google/go-cmp/cmp"
@@ -52,12 +52,15 @@ import (
52 52
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
53 53
 	"k8s.io/apimachinery/pkg/util/runtime"
54 54
 	"k8s.io/client-go/kubernetes"
55
+	"k8s.io/client-go/tools/cache"
55 56
 	hapi_chart "k8s.io/helm/pkg/proto/hapi/chart"
56 57
 	hapi_release "k8s.io/helm/pkg/proto/hapi/release"
57 58
 
58 59
 	"github.com/weaveworks/flux/git"
60
+	"github.com/weaveworks/flux/integrations/apis/flux.weave.works/v1beta1"
59 61
 	fluxv1beta1 "github.com/weaveworks/flux/integrations/apis/flux.weave.works/v1beta1"
60 62
 	ifclientset "github.com/weaveworks/flux/integrations/client/clientset/versioned"
63
+	iflister "github.com/weaveworks/flux/integrations/client/listers/flux.weave.works/v1beta1"
61 64
 	helmop "github.com/weaveworks/flux/integrations/helm"
62 65
 	"github.com/weaveworks/flux/integrations/helm/release"
63 66
 	"github.com/weaveworks/flux/integrations/helm/status"
@@ -75,13 +78,10 @@ const (
75 78
 	ReasonSuccess          = "HelmSuccess"
76 79
 )
77 80
 
78
-type Polling struct {
79
-	Interval time.Duration
80
-}
81
-
82 81
 type Clients struct {
83 82
 	KubeClient kubernetes.Clientset
84 83
 	IfClient   ifclientset.Clientset
84
+	FhrLister  iflister.HelmReleaseLister
85 85
 }
86 86
 
87 87
 type Config struct {
@@ -108,13 +108,19 @@ type clone struct {
108 108
 	head   string
109 109
 }
110 110
 
111
+// ReleaseQueue is an add-only workqueue.RateLimitingInterface
112
+type ReleaseQueue interface {
113
+	AddRateLimited(item interface{})
114
+}
115
+
111 116
 type ChartChangeSync struct {
112
-	Polling
113
-	logger     log.Logger
114
-	kubeClient kubernetes.Clientset
115
-	ifClient   ifclientset.Clientset
116
-	release    *release.Release
117
-	config     Config
117
+	logger       log.Logger
118
+	kubeClient   kubernetes.Clientset
119
+	ifClient     ifclientset.Clientset
120
+	fhrLister    iflister.HelmReleaseLister
121
+	release      *release.Release
122
+	releaseQueue ReleaseQueue
123
+	config       Config
118 124
 
119 125
 	mirrors *git.Mirrors
120 126
 
@@ -124,17 +130,18 @@ type ChartChangeSync struct {
124 130
 	namespace string
125 131
 }
126 132
 
127
-func New(logger log.Logger, polling Polling, clients Clients, release *release.Release, config Config, namespace string, statusUpdater *status.Updater) *ChartChangeSync {
133
+func New(logger log.Logger, clients Clients, release *release.Release, releaseQueue ReleaseQueue, config Config, namespace string) *ChartChangeSync {
128 134
 	return &ChartChangeSync{
129
-		logger:     logger,
130
-		Polling:    polling,
131
-		kubeClient: clients.KubeClient,
132
-		ifClient:   clients.IfClient,
133
-		release:    release,
134
-		config:     config.WithDefaults(),
135
-		mirrors:    git.NewMirrors(),
136
-		clones:     make(map[string]clone),
137
-		namespace:  namespace,
135
+		logger:       logger,
136
+		kubeClient:   clients.KubeClient,
137
+		ifClient:     clients.IfClient,
138
+		fhrLister:    clients.FhrLister,
139
+		release:      release,
140
+		releaseQueue: releaseQueue,
141
+		config:       config.WithDefaults(),
142
+		mirrors:      git.NewMirrors(),
143
+		clones:       make(map[string]clone),
144
+		namespace:    namespace,
138 145
 	}
139 146
 }
140 147
 
@@ -142,7 +149,8 @@ func New(logger log.Logger, polling Polling, clients Clients, release *release.R
142 149
 // Helm releases in the cluster, what HelmRelease declare, and
143 150
 // changes in the git repos mentioned by any HelmRelease.
144 151
 func (chs *ChartChangeSync) Run(stopCh <-chan struct{}, errc chan error, wg *sync.WaitGroup) {
145
-	chs.logger.Log("info", "Starting charts sync loop")
152
+	chs.logger.Log("info", "starting git chart sync loop")
153
+
146 154
 	wg.Add(1)
147 155
 	go func() {
148 156
 		defer runtime.HandleCrash()
@@ -151,109 +159,101 @@ func (chs *ChartChangeSync) Run(stopCh <-chan struct{}, errc chan error, wg *syn
151 159
 			wg.Done()
152 160
 		}()
153 161
 
154
-		ticker := time.NewTicker(chs.Polling.Interval)
155
-		defer ticker.Stop()
156
-
157 162
 		for {
158 163
 			select {
159
-			case reposChanged := <-chs.mirrors.Changes():
160
-				// TODO(michael): the inefficient way, for now, until
161
-				// it's clear how to better optimalise it
162
-				resources, err := chs.getCustomResources()
163
-				if err != nil {
164
-					chs.logger.Log("warning", "failed to get custom resources", "err", err)
165
-					continue
166
-				}
167
-				for _, fhr := range resources {
168
-					if fhr.Spec.ChartSource.GitChartSource == nil {
169
-						continue
170
-					}
171
-
172
-					repoURL := fhr.Spec.ChartSource.GitChartSource.GitURL
173
-					repoName := mirrorName(fhr.Spec.ChartSource.GitChartSource)
174
-
175
-					if _, ok := reposChanged[repoName]; !ok {
164
+			case mirrorsChanged := <-chs.mirrors.Changes():
165
+				for mirror := range mirrorsChanged {
166
+					resources, err := chs.getCustomResourcesForMirror(mirror)
167
+					if err != nil {
168
+						chs.logger.Log("warning", "failed to get custom resources", "err", err)
176 169
 						continue
177 170
 					}
178 171
 
179
-					repo, ok := chs.mirrors.Get(repoName)
172
+					// Retrieve the mirror we got a change signal for
173
+					repo, ok := chs.mirrors.Get(mirror)
180 174
 					if !ok {
181 175
 						// Then why .. did you say .. it had changed? It may have been removed. Add it back and let it signal again.
182
-						chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionUnknown, ReasonGitNotReady, "git mirror missing; starting mirroring again")
183
-						chs.logger.Log("warning", "mirrored git repo disappeared after signalling change", "repo", repoName)
184
-						chs.maybeMirror(fhr)
176
+						chs.logger.Log("warning", "mirrored git repo disappeared after signalling change", "repo", mirror)
177
+						for _, fhr := range resources {
178
+							chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionUnknown, ReasonGitNotReady, "git mirror missing; starting mirroring again")
179
+							chs.maybeMirror(fhr)
180
+						}
185 181
 						continue
186 182
 					}
187 183
 
184
+					// Ensure the repo is ready
188 185
 					status, err := repo.Status()
189 186
 					if status != git.RepoReady {
190
-						chs.logger.Log("info", "repo not ready yet, while attempting chart sync", "repo", repoURL, "status", string(status))
191
-						// TODO(michael) log if there's a problem with the following?
192
-						chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionUnknown, ReasonGitNotReady, err.Error())
193
-						continue
194
-					}
195
-
196
-					ref := fhr.Spec.ChartSource.GitChartSource.RefOrDefault()
197
-					path := fhr.Spec.ChartSource.GitChartSource.Path
198
-					releaseName := release.GetReleaseName(fhr)
199
-
200
-					ctx, cancel := context.WithTimeout(context.Background(), helmop.GitOperationTimeout)
201
-					refHead, err := repo.Revision(ctx, ref)
202
-					cancel()
203
-					if err != nil {
204
-						chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionFalse, ReasonGitNotReady, "problem cloning from local git mirror: "+err.Error())
205
-						chs.logger.Log("warning", "could not get revision for ref while checking for changes", "repo", repoURL, "ref", ref, "err", err)
187
+						chs.logger.Log("info", "repo not ready yet, while attempting chart sync", "repo", mirror, "status", string(status))
188
+						for _, fhr := range resources {
189
+							// TODO(michael) log if there's a problem with the following?
190
+							chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionUnknown, ReasonGitNotReady, err.Error())
191
+						}
206 192
 						continue
207 193
 					}
208 194
 
209
-					// This FHR is using a git repo; and, it appears to have had commits since we last saw it.
210
-					// Check explicitly whether we should update its clone.
211
-					chs.clonesMu.Lock()
212
-					cloneForChart, ok := chs.clones[releaseName]
213
-					chs.clonesMu.Unlock()
195
+					// Determine if we need to update the clone and
196
+					// schedule an upgrade for every HelmRelease that
197
+					// makes use of the mirror
198
+					for _, fhr := range resources {
199
+						ref := fhr.Spec.ChartSource.GitChartSource.RefOrDefault()
200
+						path := fhr.Spec.ChartSource.GitChartSource.Path
201
+						releaseName := release.GetReleaseName(fhr)
214 202
 
215
-					if ok { // found clone
216 203
 						ctx, cancel := context.WithTimeout(context.Background(), helmop.GitOperationTimeout)
217
-						commits, err := repo.CommitsBetween(ctx, cloneForChart.head, refHead, path)
204
+						refHead, err := repo.Revision(ctx, ref)
218 205
 						cancel()
219 206
 						if err != nil {
220 207
 							chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionFalse, ReasonGitNotReady, "problem cloning from local git mirror: "+err.Error())
221
-							chs.logger.Log("warning", "could not get revision for ref while checking for changes", "repo", repoURL, "ref", ref, "err", err)
208
+							chs.logger.Log("warning", "could not get revision for ref while checking for changes", "resource", fhr.ResourceID().String(), "repo", mirror, "ref", ref, "err", err)
222 209
 							continue
223 210
 						}
224
-						ok = len(commits) == 0
225
-					}
226 211
 
227
-					if !ok { // didn't find clone, or it needs updating
228
-						ctx, cancel := context.WithTimeout(context.Background(), helmop.GitOperationTimeout)
229
-						newClone, err := repo.Export(ctx, refHead)
230
-						cancel()
231
-						if err != nil {
232
-							chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionFalse, ReasonGitNotReady, "problem cloning from local git mirror: "+err.Error())
233
-							chs.logger.Log("warning", "could not clone from mirror while checking for changes", "repo", repoURL, "ref", ref, "err", err)
234
-							continue
235
-						}
236
-						newCloneForChart := clone{remote: repoURL, ref: ref, head: refHead, export: newClone}
212
+						// The git repo of this appears to have had commits since we last saw it,
213
+						// check explicitly whether we should update its clone.
237 214
 						chs.clonesMu.Lock()
238
-						chs.clones[releaseName] = newCloneForChart
215
+						cloneForChart, ok := chs.clones[releaseName]
239 216
 						chs.clonesMu.Unlock()
240
-						if cloneForChart.export != nil {
241
-							cloneForChart.export.Clean()
217
+
218
+						if ok { // found clone
219
+							ctx, cancel := context.WithTimeout(context.Background(), helmop.GitOperationTimeout)
220
+							commits, err := repo.CommitsBetween(ctx, cloneForChart.head, refHead, path)
221
+							cancel()
222
+							if err != nil {
223
+								chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionFalse, ReasonGitNotReady, "problem cloning from local git mirror: "+err.Error())
224
+								chs.logger.Log("warning", "could not get revision for ref while checking for changes", "resource", fhr.ResourceID().String(), "repo", mirror, "ref", ref, "err", err)
225
+								continue
226
+							}
227
+							ok = len(commits) == 0
242 228
 						}
243
-					}
244 229
 
245
-					chs.reconcileReleaseDef(fhr)
246
-				}
247
-			case <-ticker.C:
248
-				// Re-release any chart releases that have apparently
249
-				// changed in the cluster.
250
-				chs.logger.Log("info", fmt.Sprint("Start of releasesync"))
251
-				err := chs.reapplyReleaseDefs()
252
-				if err != nil {
253
-					chs.logger.Log("error", fmt.Sprintf("Failure to do manual release sync: %s", err))
254
-				}
255
-				chs.logger.Log("info", fmt.Sprint("End of releasesync"))
230
+						if !ok { // didn't find clone, or it needs updating
231
+							ctx, cancel := context.WithTimeout(context.Background(), helmop.GitOperationTimeout)
232
+							newClone, err := repo.Export(ctx, refHead)
233
+							cancel()
234
+							if err != nil {
235
+								chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionFalse, ReasonGitNotReady, "problem cloning from local git mirror: "+err.Error())
236
+								chs.logger.Log("warning", "could not clone from mirror while checking for changes", "resource", fhr.ResourceID().String(), "repo", mirror, "ref", ref, "err", err)
237
+								continue
238
+							}
239
+							newCloneForChart := clone{remote: mirror, ref: ref, head: refHead, export: newClone}
240
+							chs.clonesMu.Lock()
241
+							chs.clones[releaseName] = newCloneForChart
242
+							chs.clonesMu.Unlock()
243
+							if cloneForChart.export != nil {
244
+								cloneForChart.export.Clean()
245
+							}
246
+						}
256 247
 
248
+						// Enqueue release
249
+						cacheKey, err := cache.MetaNamespaceKeyFunc(fhr.GetObjectMeta())
250
+						if err != nil {
251
+							continue
252
+						}
253
+						chs.logger.Log("info", "enqueing release upgrade due to change in git chart source", "resource", fhr.ResourceID().String())
254
+						chs.releaseQueue.AddRateLimited(cacheKey)
255
+					}
256
+				}
257 257
 			case <-stopCh:
258 258
 				chs.logger.Log("stopping", "true")
259 259
 				return
@@ -315,7 +315,7 @@ func (chs *ChartChangeSync) reconcileReleaseDef(fhr fluxv1beta1.HelmRelease) {
315 315
 		// is being referenced in the chart source.
316 316
 		if ok {
317 317
 			ok = chartClone.remote == chartSource.GitURL && chartClone.ref == chartSource.RefOrDefault()
318
-			if !ok  {
318
+			if !ok {
319 319
 				if chartClone.export != nil {
320 320
 					chartClone.export.Clean()
321 321
 				}
@@ -332,12 +332,12 @@ func (chs *ChartChangeSync) reconcileReleaseDef(fhr fluxv1beta1.HelmRelease) {
332 332
 			if !ok {
333 333
 				chs.maybeMirror(fhr)
334 334
 				chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionUnknown, ReasonGitNotReady, "git repo "+chartSource.GitURL+" not mirrored yet")
335
-				chs.logger.Log("info", "chart repo not cloned yet", "releaseName", releaseName, "resource", fmt.Sprintf("%s:%s/%s", fhr.Namespace, fhr.Kind, fhr.Name))
335
+				chs.logger.Log("info", "chart repo not cloned yet", "resource", fhr.ResourceID().String())
336 336
 			} else {
337 337
 				status, err := repo.Status()
338 338
 				if status != git.RepoReady {
339 339
 					chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionUnknown, ReasonGitNotReady, "git repo not mirrored yet: "+err.Error())
340
-					chs.logger.Log("info", "chart repo not ready yet", "releaseName", releaseName, "resource", fmt.Sprintf("%s:%s/%s", fhr.Namespace, fhr.Kind, fhr.Name), "status", string(status), "err", err)
340
+					chs.logger.Log("info", "chart repo not ready yet", "resource", fhr.ResourceID().String(), "status", string(status), "err", err)
341 341
 				}
342 342
 			}
343 343
 			return
@@ -349,7 +349,7 @@ func (chs *ChartChangeSync) reconcileReleaseDef(fhr fluxv1beta1.HelmRelease) {
349 349
 		if chs.config.UpdateDeps && !fhr.Spec.ChartSource.GitChartSource.SkipDepUpdate {
350 350
 			if err := updateDependencies(chartPath, ""); err != nil {
351 351
 				chs.setCondition(&fhr, fluxv1beta1.HelmReleaseReleased, v1.ConditionFalse, ReasonDependencyFailed, err.Error())
352
-				chs.logger.Log("warning", "Failed to update chart dependencies", "namespace", fhr.Namespace, "name", fhr.Name, "error", err)
352
+				chs.logger.Log("warning", "failed to update chart dependencies", "resource", fhr.ResourceID().String(), "err", err)
353 353
 				return
354 354
 			}
355 355
 		}
@@ -358,7 +358,7 @@ func (chs *ChartChangeSync) reconcileReleaseDef(fhr fluxv1beta1.HelmRelease) {
358 358
 		path, err := ensureChartFetched(chs.config.ChartCache, chartSource)
359 359
 		if err != nil {
360 360
 			chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionFalse, ReasonDownloadFailed, "chart download failed: "+err.Error())
361
-			chs.logger.Log("info", "chart download failed", "releaseName", releaseName, "resource", fhr.ResourceID().String(), "err", err)
361
+			chs.logger.Log("info", "chart download failed", "resource", fhr.ResourceID().String(), "err", err)
362 362
 			return
363 363
 		}
364 364
 		chs.setCondition(&fhr, fluxv1beta1.HelmReleaseChartFetched, v1.ConditionTrue, ReasonDownloaded, "chart fetched: "+filepath.Base(path))
@@ -370,7 +370,7 @@ func (chs *ChartChangeSync) reconcileReleaseDef(fhr fluxv1beta1.HelmRelease) {
370 370
 		_, err := chs.release.Install(chartPath, releaseName, fhr, release.InstallAction, opts, &chs.kubeClient)
371 371
 		if err != nil {
372 372
 			chs.setCondition(&fhr, fluxv1beta1.HelmReleaseReleased, v1.ConditionFalse, ReasonInstallFailed, err.Error())
373
-			chs.logger.Log("warning", "Failed to install chart", "namespace", fhr.Namespace, "name", fhr.Name, "error", err)
373
+			chs.logger.Log("warning", "failed to install chart", "resource", fhr.ResourceID().String(), "err", err)
374 374
 			return
375 375
 		}
376 376
 		chs.setCondition(&fhr, fluxv1beta1.HelmReleaseReleased, v1.ConditionTrue, ReasonSuccess, "helm install succeeded")
@@ -382,40 +382,33 @@ func (chs *ChartChangeSync) reconcileReleaseDef(fhr fluxv1beta1.HelmRelease) {
382 382
 
383 383
 	changed, err := chs.shouldUpgrade(chartPath, rel, fhr)
384 384
 	if err != nil {
385
-		chs.logger.Log("warning", "Unable to determine if release has changed", "namespace", fhr.Namespace, "name", fhr.Name, "error", err)
385
+		chs.logger.Log("warning", "unable to determine if release has changed", "resource", fhr.ResourceID().String(), "err", err)
386 386
 		return
387 387
 	}
388 388
 	if changed {
389
-		_, err := chs.release.Install(chartPath, releaseName, fhr, release.UpgradeAction, opts, &chs.kubeClient)
389
+		cFhr, err := chs.ifClient.FluxV1beta1().HelmReleases(fhr.Namespace).Get(fhr.Name, metav1.GetOptions{})
390
+		if err != nil {
391
+			chs.logger.Log("warning", "failed to retrieve HelmRelease scheduled for upgrade", "resource", fhr.ResourceID().String(), "err", err)
392
+			return
393
+		}
394
+		if diff := cmp.Diff(fhr.Spec, cFhr.Spec); diff != "" {
395
+			chs.logger.Log("warning", "HelmRelease spec has diverged since we calculated if we should upgrade, skipping upgrade", "resource", fhr.ResourceID().String())
396
+			return
397
+		}
398
+		_, err = chs.release.Install(chartPath, releaseName, fhr, release.UpgradeAction, opts, &chs.kubeClient)
390 399
 		if err != nil {
391 400
 			chs.setCondition(&fhr, fluxv1beta1.HelmReleaseReleased, v1.ConditionFalse, ReasonUpgradeFailed, err.Error())
392
-			chs.logger.Log("warning", "Failed to upgrade chart", "namespace", fhr.Namespace, "name", fhr.Name, "error", err)
401
+			chs.logger.Log("warning", "failed to upgrade chart", "resource", fhr.ResourceID().String(), "err", err)
393 402
 			return
394 403
 		}
395 404
 		chs.setCondition(&fhr, fluxv1beta1.HelmReleaseReleased, v1.ConditionTrue, ReasonSuccess, "helm upgrade succeeded")
396 405
 		if err = status.UpdateReleaseRevision(chs.ifClient.FluxV1beta1().HelmReleases(fhr.Namespace), fhr, chartRevision); err != nil {
397
-			chs.logger.Log("warning", "could not update the release revision", "namespace", fhr.Namespace, "resource", fhr.Name, "err", err)
406
+			chs.logger.Log("warning", "could not update the release revision", "resource", fhr.ResourceID().String(), "err", err)
398 407
 		}
399 408
 		return
400 409
 	}
401 410
 }
402 411
 
403
-// reapplyReleaseDefs goes through the resource definitions and
404
-// reconciles them with Helm releases. This is a "backstop" for the
405
-// other sync processes, to cover the case of a release being changed
406
-// out-of-band (e.g., by someone using `helm upgrade`).
407
-func (chs *ChartChangeSync) reapplyReleaseDefs() error {
408
-	resources, err := chs.getCustomResources()
409
-	if err != nil {
410
-		return fmt.Errorf("failed to get HelmRelease resources from the API server: %s", err.Error())
411
-	}
412
-
413
-	for _, fhr := range resources {
414
-		chs.reconcileReleaseDef(fhr)
415
-	}
416
-	return nil
417
-}
418
-
419 412
 // DeleteRelease deletes the helm release associated with a
420 413
 // HelmRelease. This exists mainly so that the operator code can
421 414
 // call it when it is handling a resource deletion.
@@ -424,7 +417,7 @@ func (chs *ChartChangeSync) DeleteRelease(fhr fluxv1beta1.HelmRelease) {
424 417
 	name := release.GetReleaseName(fhr)
425 418
 	err := chs.release.Delete(name)
426 419
 	if err != nil {
427
-		chs.logger.Log("warning", "Chart release not deleted", "release", name, "error", err)
420
+		chs.logger.Log("warning", "chart release not deleted", "resource", fhr.ResourceID().String(), "release", name, "err", err)
428 421
 	}
429 422
 
430 423
 	// Remove the clone we may have for this HelmRelease
@@ -441,39 +434,27 @@ func (chs *ChartChangeSync) DeleteRelease(fhr fluxv1beta1.HelmRelease) {
441 434
 
442 435
 // SyncMirrors instructs all mirrors to refresh from their upstream.
443 436
 func (chs *ChartChangeSync) SyncMirrors() {
444
-	chs.logger.Log("info", "Starting mirror sync")
437
+	chs.logger.Log("info", "starting mirror sync")
445 438
 	for _, err := range chs.mirrors.RefreshAll(chs.config.GitTimeout) {
446
-		chs.logger.Log("error", fmt.Sprintf("Failure while syncing mirror: %s", err))
439
+		chs.logger.Log("error", fmt.Sprintf("failure while syncing mirror: %s", err))
447 440
 	}
448
-	chs.logger.Log("info", "Finished syncing mirrors")
441
+	chs.logger.Log("info", "finished syncing mirrors")
449 442
 }
450 443
 
451
-// getCustomResources assembles all custom resources in all namespaces
452
-// or in the allowed namespace if specified
453
-func (chs *ChartChangeSync) getCustomResources() ([]fluxv1beta1.HelmRelease, error) {
454
-	var namespaces []string
455
-	if chs.namespace != "" {
456
-		namespaces = append(namespaces, chs.namespace)
457
-	} else {
458
-		nso, err := chs.kubeClient.CoreV1().Namespaces().List(metav1.ListOptions{})
459
-		if err != nil {
460
-			return nil, fmt.Errorf("Failure while retrieving kubernetes namespaces: %s", err)
461
-		}
462
-		for _, n := range nso.Items {
463
-			namespaces = append(namespaces, n.GetName())
464
-		}
444
+// getCustomResourcesForMirror retrieves all the resources that make
445
+// use of the given mirror from the lister.
446
+func (chs *ChartChangeSync) getCustomResourcesForMirror(mirror string) ([]fluxv1beta1.HelmRelease, error) {
447
+	var fhrs []v1beta1.HelmRelease
448
+	list, err := chs.fhrLister.List(labels.Everything())
449
+	if err != nil {
450
+		return nil, err
465 451
 	}
466 452
 
467
-	var fhrs []fluxv1beta1.HelmRelease
468
-	for _, ns := range namespaces {
469
-		list, err := chs.ifClient.FluxV1beta1().HelmReleases(ns).List(metav1.ListOptions{})
470
-		if err != nil {
471
-			return nil, err
472
-		}
473
-
474
-		for _, fhr := range list.Items {
475
-			fhrs = append(fhrs, fhr)
453
+	for _, fhr := range list {
454
+		if mirror != mirrorName(fhr.Spec.GitChartSource) {
455
+			continue
476 456
 		}
457
+		fhrs = append(fhrs, *fhr)
477 458
 	}
478 459
 	return fhrs, nil
479 460
 }
@@ -547,7 +528,7 @@ func sortChartFields(c *hapi_chart.Chart) *hapi_chart.Chart {
547 528
 // doing a dry run install from the chart in the git repo.
548 529
 func (chs *ChartChangeSync) shouldUpgrade(chartsRepo string, currRel *hapi_release.Release, fhr fluxv1beta1.HelmRelease) (bool, error) {
549 530
 	if currRel == nil {
550
-		return false, fmt.Errorf("No Chart release provided for %v", fhr.GetName())
531
+		return false, fmt.Errorf("no chart release provided for %v", fhr.GetName())
551 532
 	}
552 533
 
553 534
 	currVals := currRel.GetConfig()
@@ -566,18 +547,18 @@ func (chs *ChartChangeSync) shouldUpgrade(chartsRepo string, currRel *hapi_relea
566 547
 	// compare values && Chart
567 548
 	if diff := cmp.Diff(currVals, desVals); diff != "" {
568 549
 		if chs.config.LogDiffs {
569
-			chs.logger.Log("error", fmt.Sprintf("Release %s: values have diverged due to manual Chart release", currRel.GetName()), "diff", diff)
550
+			chs.logger.Log("error", fmt.Sprintf("release %s: values have diverged due to manual chart release", currRel.GetName()), "resource", fhr.ResourceID().String(), "diff", diff)
570 551
 		} else {
571
-			chs.logger.Log("error", fmt.Sprintf("Release %s: values have diverged due to manual Chart release", currRel.GetName()))
552
+			chs.logger.Log("error", fmt.Sprintf("release %s: values have diverged due to manual chart release", currRel.GetName()), "resource", fhr.ResourceID().String())
572 553
 		}
573 554
 		return true, nil
574 555
 	}
575 556
 
576 557
 	if diff := cmp.Diff(sortChartFields(currChart), sortChartFields(desChart)); diff != "" {
577 558
 		if chs.config.LogDiffs {
578
-			chs.logger.Log("error", fmt.Sprintf("Release %s: Chart has diverged due to manual Chart release", currRel.GetName()), "diff", diff)
559
+			chs.logger.Log("error", fmt.Sprintf("release %s: chart has diverged due to manual chart release", currRel.GetName()), "resource", fhr.ResourceID().String(), "diff", diff)
579 560
 		} else {
580
-			chs.logger.Log("error", fmt.Sprintf("Release %s: Chart has diverged due to manual Chart release", currRel.GetName()))
561
+			chs.logger.Log("error", fmt.Sprintf("release %s: chart has diverged due to manual chart release", currRel.GetName()), "resource", fhr.ResourceID().String())
581 562
 		}
582 563
 		return true, nil
583 564
 	}

+ 1
- 1
integrations/helm/helm.go View File

@@ -75,7 +75,7 @@ func ClientSetup(logger log.Logger, kubeClient *kubernetes.Clientset, tillerOpts
75 75
 	for {
76 76
 		helmClient, host, err = newClient(kubeClient, tillerOpts)
77 77
 		if err != nil {
78
-			logger.Log("error", fmt.Sprintf("Error creating helm client: %s", err.Error()))
78
+			logger.Log("error", fmt.Sprintf("error creating helm client: %s", err.Error()))
79 79
 			time.Sleep(20 * time.Second)
80 80
 			continue
81 81
 		}

+ 5
- 4
integrations/helm/http/daemon/server.go View File

@@ -3,14 +3,15 @@ package daemon
3 3
 import (
4 4
 	"context"
5 5
 	"fmt"
6
+	"net/http"
7
+	"sync/atomic"
8
+	"time"
9
+
6 10
 	"github.com/go-kit/kit/log"
7 11
 	"github.com/gorilla/mux"
8 12
 	"github.com/prometheus/client_golang/prometheus/promhttp"
9 13
 	"github.com/weaveworks/flux/integrations/helm/api"
10 14
 	transport "github.com/weaveworks/flux/integrations/helm/http"
11
-	"net/http"
12
-	"sync/atomic"
13
-	"time"
14 15
 )
15 16
 
16 17
 // ListenAndServe starts a HTTP server instrumented with Prometheus metrics,
@@ -37,7 +38,7 @@ func ListenAndServe(listenAddr string, apiServer api.Server, logger log.Logger,
37 38
 		IdleTimeout:  15 * time.Second,
38 39
 	}
39 40
 
40
-	logger.Log("info", fmt.Sprintf("Starting HTTP server on %s", listenAddr))
41
+	logger.Log("info", fmt.Sprintf("starting HTTP server on %s", listenAddr))
41 42
 
42 43
 	// run server in background
43 44
 	go func() {

+ 30
- 41
integrations/helm/operator/operator.go View File

@@ -7,7 +7,6 @@ import (
7 7
 	"time"
8 8
 
9 9
 	"github.com/go-kit/kit/log"
10
-	"github.com/golang/glog"
11 10
 	"github.com/google/go-cmp/cmp"
12 11
 	corev1 "k8s.io/api/core/v1"
13 12
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -40,12 +39,9 @@ const (
40 39
 	// a HelmRelease fails to be released/updated
41 40
 	ErrChartSync = "ErrChartSync"
42 41
 
43
-	// MessageChartSynced - the message used for Events when a resource
44
-	// fails to sync due to failing to release the Chart
45
-	MessageChartSynced = "Chart managed by HelmRelease processed successfully"
46
-	// MessageErrChartSync - the message used for an Event fired when a HelmRelease
47
-	// is synced successfully
48
-	MessageErrChartSync = "Chart %s managed by HelmRelease failed to be processed"
42
+	// MessageChartSynced - the message used for an Event fired when a HelmRelease
43
+	// is synced.
44
+	MessageChartSynced = "Chart managed by HelmRelease processed"
49 45
 )
50 46
 
51 47
 // Controller is the operator implementation for HelmRelease resources
@@ -76,13 +72,13 @@ func New(
76 72
 	logReleaseDiffs bool,
77 73
 	kubeclientset kubernetes.Interface,
78 74
 	fhrInformer fhrv1.HelmReleaseInformer,
75
+	releaseWorkqueue workqueue.RateLimitingInterface,
79 76
 	sync *chartsync.ChartChangeSync) *Controller {
80 77
 
81 78
 	// Add helm-operator types to the default Kubernetes Scheme so Events can be
82 79
 	// logged for helm-operator types.
83 80
 	ifscheme.AddToScheme(scheme.Scheme)
84 81
 	eventBroadcaster := record.NewBroadcaster()
85
-	eventBroadcaster.StartLogging(glog.Infof)
86 82
 	eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")})
87 83
 	recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
88 84
 
@@ -91,18 +87,16 @@ func New(
91 87
 		logDiffs:         logReleaseDiffs,
92 88
 		fhrLister:        fhrInformer.Lister(),
93 89
 		fhrSynced:        fhrInformer.Informer().HasSynced,
94
-		releaseWorkqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "ChartRelease"),
90
+		releaseWorkqueue: releaseWorkqueue,
95 91
 		recorder:         recorder,
96 92
 		sync:             sync,
97 93
 	}
98 94
 
99
-	controller.logger.Log("info", "Setting up event handlers")
95
+	controller.logger.Log("info", "setting up event handlers")
100 96
 
101 97
 	// ----- EVENT HANDLERS for HelmRelease resources change ---------
102 98
 	fhrInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
103 99
 		AddFunc: func(new interface{}) {
104
-			controller.logger.Log("info", "CREATING release")
105
-			controller.logger.Log("info", "Custom Resource driven release install")
106 100
 			_, ok := checkCustomResourceType(controller.logger, new)
107 101
 			if ok {
108 102
 				controller.enqueueJob(new)
@@ -118,7 +112,7 @@ func New(
118 112
 			}
119 113
 		},
120 114
 	})
121
-	controller.logger.Log("info", "Event handlers set up")
115
+	controller.logger.Log("info", "event handlers set up")
122 116
 
123 117
 	return controller
124 118
 }
@@ -131,16 +125,16 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}, wg *sync.WaitG
131 125
 	defer runtime.HandleCrash()
132 126
 	defer c.releaseWorkqueue.ShutDown()
133 127
 
134
-	c.logger.Log("info", "Starting operator")
128
+	c.logger.Log("info", "starting operator")
135 129
 	// Wait for the caches to be synced before starting workers
136
-	c.logger.Log("info", "Waiting for informer caches to sync")
130
+	c.logger.Log("info", "waiting for informer caches to sync")
137 131
 
138 132
 	if ok := cache.WaitForCacheSync(stopCh, c.fhrSynced); !ok {
139 133
 		return errors.New("failed to wait for caches to sync")
140 134
 	}
141
-	c.logger.Log("info", "Informer caches synced")
135
+	c.logger.Log("info", "unformer caches synced")
142 136
 
143
-	c.logger.Log("info", "Starting workers")
137
+	c.logger.Log("info", "starting workers")
144 138
 	for i := 0; i < threadiness; i++ {
145 139
 		wg.Add(1)
146 140
 		go wait.Until(c.runWorker, time.Second, stopCh)
@@ -150,7 +144,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}, wg *sync.WaitG
150 144
 	for i := 0; i < threadiness; i++ {
151 145
 		wg.Done()
152 146
 	}
153
-	c.logger.Log("info", "Stopping workers")
147
+	c.logger.Log("info", "stopping workers")
154 148
 
155 149
 	return nil
156 150
 }
@@ -166,11 +160,7 @@ func (c *Controller) runWorker() {
166 160
 // processNextWorkItem will read a single work item off the workqueue and
167 161
 // attempt to process it, by calling the syncHandler.
168 162
 func (c *Controller) processNextWorkItem() bool {
169
-	c.logger.Log("debug", "Processing next work queue job ...")
170
-
171 163
 	obj, shutdown := c.releaseWorkqueue.Get()
172
-	c.logger.Log("debug", fmt.Sprintf("PROCESSING item [%#v]", obj))
173
-
174 164
 	if shutdown {
175 165
 		return false
176 166
 	}
@@ -197,7 +187,7 @@ func (c *Controller) processNextWorkItem() bool {
197 187
 			// Forget not to get into a loop of attempting to
198 188
 			// process a work item that is invalid.
199 189
 			c.releaseWorkqueue.Forget(obj)
200
-			runtime.HandleError(fmt.Errorf("Expected string in workqueue but got %#v", obj))
190
+			runtime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj))
201 191
 
202 192
 			return nil
203 193
 		}
@@ -205,14 +195,11 @@ func (c *Controller) processNextWorkItem() bool {
205 195
 		// HelmRelease resource to sync the corresponding Chart release.
206 196
 		// If the sync failed, then we return while the item will get requeued
207 197
 		if err := c.syncHandler(key); err != nil {
208
-			return fmt.Errorf("error syncing '%s': %s", key, err.Error())
198
+			return fmt.Errorf("errored syncing HelmRelease '%s': %s", key, err.Error())
209 199
 		}
210 200
 		// If no error occurs we Forget this item so it does not
211 201
 		// get queued again until another change happens.
212 202
 		c.releaseWorkqueue.Forget(obj)
213
-
214
-		c.logger.Log("info", fmt.Sprintf("Successfully synced '%s'", key))
215
-
216 203
 		return nil
217 204
 	}(obj)
218 205
 
@@ -226,13 +213,11 @@ func (c *Controller) processNextWorkItem() bool {
226 213
 // syncHandler acts according to the action
227 214
 // 		Deletes/creates or updates a Chart release
228 215
 func (c *Controller) syncHandler(key string) error {
229
-	c.logger.Log("debug", fmt.Sprintf("Starting to sync cache key %s", key))
230
-
231 216
 	// Retrieve namespace and Custom Resource name from the key
232 217
 	namespace, name, err := cache.SplitMetaNamespaceKey(key)
233 218
 	if err != nil {
234
-		c.logger.Log("info", fmt.Sprintf("Invalid cache key: %v", err))
235
-		runtime.HandleError(fmt.Errorf("Invalid cache key: %s", key))
219
+		c.logger.Log("error", fmt.Sprintf("key '%s' is invalid: %v", key, err))
220
+		runtime.HandleError(fmt.Errorf("key '%s' is invalid", key))
236 221
 		return nil
237 222
 	}
238 223
 
@@ -297,19 +282,23 @@ func (c *Controller) enqueueUpdateJob(old, new interface{}) {
297 282
 		return
298 283
 	}
299 284
 
300
-	if diff := cmp.Diff(oldFhr.Spec, newFhr.Spec); diff != "" {
301
-		c.logger.Log("info", "UPGRADING release")
302
-		if c.logDiffs {
303
-			c.logger.Log("info", "Custom Resource driven release upgrade", "diff", diff)
304
-		} else {
305
-			c.logger.Log("info", "Custom Resource driven release upgrade")
306
-		}
307
-		c.enqueueJob(new)
285
+	log := []string{"info", "enqueuing release upgrade"}
286
+	if diff := cmp.Diff(oldFhr.Spec, newFhr.Spec); diff != "" && c.logDiffs {
287
+		log = append(log, "diff", diff)
288
+	}
289
+	log = append(log, "resource", newFhr.ResourceID().String())
290
+
291
+	l := make([]interface{}, len(log))
292
+	for i, v := range log {
293
+		l[i] = v
308 294
 	}
295
+
296
+	c.logger.Log(l...)
297
+
298
+	c.enqueueJob(new)
309 299
 }
310 300
 
311 301
 func (c *Controller) deleteRelease(fhr flux_v1beta1.HelmRelease) {
312
-	c.logger.Log("info", "DELETING release")
313
-	c.logger.Log("info", "Custom Resource driven release deletion")
302
+	c.logger.Log("info", "deleting release", "resource", fhr.ResourceID().String())
314 303
 	c.sync.DeleteRelease(fhr)
315 304
 }

+ 8
- 16
integrations/helm/status/conditions.go View File

@@ -1,17 +1,14 @@
1 1
 package status
2 2
 
3 3
 import (
4
-	"encoding/json"
5
-
6 4
 	"github.com/weaveworks/flux/integrations/apis/flux.weave.works/v1beta1"
7 5
 	v1beta1client "github.com/weaveworks/flux/integrations/client/clientset/versioned/typed/flux.weave.works/v1beta1"
8
-	"k8s.io/apimachinery/pkg/types"
9 6
 )
10 7
 
11 8
 // We can't rely on having UpdateStatus, or strategic merge patching
12 9
 // for custom resources. So we have to create an object which
13 10
 // represents the merge path or JSON patch to apply.
14
-func UpdateConditionsPatch(status *v1beta1.HelmReleaseStatus, updates ...v1beta1.HelmReleaseCondition) (types.PatchType, interface{}) {
11
+func UpdateConditionsPatch(status *v1beta1.HelmReleaseStatus, updates ...v1beta1.HelmReleaseCondition) {
15 12
 	newConditions := make([]v1beta1.HelmReleaseCondition, len(status.Conditions))
16 13
 	oldConditions := status.Conditions
17 14
 	for i, c := range oldConditions {
@@ -28,20 +25,15 @@ updates:
28 25
 		newConditions = append(newConditions, up)
29 26
 	}
30 27
 	status.Conditions = newConditions
31
-	return types.MergePatchType, map[string]interface{}{
32
-		"status": map[string]interface{}{
33
-			"conditions": newConditions,
34
-		},
35
-	}
36 28
 }
37 29
 
38
-// UpdateConditions applies the updates to the HelmRelease given, and patches the resource in the cluster.
30
+// UpdateConditions applies the updates to the HelmRelease given, and
31
+// updates the resource in the cluster.
39 32
 func UpdateConditions(client v1beta1client.HelmReleaseInterface, fhr *v1beta1.HelmRelease, updates ...v1beta1.HelmReleaseCondition) error {
40
-	t, obj := UpdateConditionsPatch(&fhr.Status, updates...)
41
-	bytes, err := json.Marshal(obj)
42
-	if err != nil {
43
-		return err
44
-	}
45
-	_, err = client.Patch(fhr.Name, t, bytes)
33
+	fhrCopy := fhr.DeepCopy()
34
+
35
+	UpdateConditionsPatch(&fhrCopy.Status, updates...)
36
+	_, err := client.UpdateStatus(fhrCopy)
37
+
46 38
 	return err
47 39
 }

+ 9
- 27
integrations/helm/status/status.go View File

@@ -14,12 +14,10 @@ correspond. Specifically,
14 14
 package status
15 15
 
16 16
 import (
17
-	"encoding/json"
18 17
 	"time"
19 18
 
20 19
 	"github.com/go-kit/kit/log"
21 20
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22
-	"k8s.io/apimachinery/pkg/types"
23 21
 	kube "k8s.io/client-go/kubernetes"
24 22
 	"k8s.io/helm/pkg/helm"
25 23
 
@@ -104,34 +102,18 @@ bail:
104 102
 }
105 103
 
106 104
 func UpdateReleaseStatus(client v1beta1client.HelmReleaseInterface, fhr v1beta1.HelmRelease, releaseName, releaseStatus string) error {
107
-	patchBytes, err := json.Marshal(map[string]interface{}{
108
-		"status": map[string]interface{}{
109
-			"releaseName":   releaseName,
110
-			"releaseStatus": releaseStatus,
111
-		},
112
-	})
113
-	if err == nil {
114
-		// CustomResources don't get
115
-		// StrategicMergePatch, for now, but since we
116
-		// want to unconditionally set the value, this
117
-		// is OK.
118
-		_, err = client.Patch(fhr.Name, types.MergePatchType, patchBytes)
119
-	}
105
+	fhr.Status.ReleaseName = releaseName
106
+	fhr.Status.ReleaseStatus = releaseStatus
107
+
108
+	_, err := client.UpdateStatus(&fhr)
109
+
120 110
 	return err
121 111
 }
122 112
 
123 113
 func UpdateReleaseRevision(client v1beta1client.HelmReleaseInterface, fhr v1beta1.HelmRelease, revision string) error {
124
-	patchBytes, err := json.Marshal(map[string]interface{}{
125
-		"status": map[string]interface{}{
126
-			"revision": revision,
127
-		},
128
-	})
129
-	if err == nil {
130
-		// CustomResources don't get
131
-		// StrategicMergePatch, for now, but since we
132
-		// want to unconditionally set the value, this
133
-		// is OK.
134
-		_, err = client.Patch(fhr.Name, types.MergePatchType, patchBytes)
135
-	}
114
+	fhr.Status.Revision = revision
115
+
116
+	_, err := client.UpdateStatus(&fhr)
117
+
136 118
 	return err
137 119
 }

Loading…
Cancel
Save