Skip to content

Commit 4a72fb9

Browse files
committed
(bugfix): rewrite the contentmanager implementation
to fix bugs associated with insufficient permissions resulting in halting reconciliation of all ClusterExtension and informer sync errors not being reported via the ClusterExtension status conditions. Signed-off-by: everettraven <[email protected]>
1 parent 5800c7f commit 4a72fb9

16 files changed

+1412
-429
lines changed

api/v1alpha1/clusterextension_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ const (
390390
// TODO(user): add more Types, here and into init()
391391
TypeInstalled = "Installed"
392392
TypeResolved = "Resolved"
393+
TypeHealthy = "Healthy"
393394

394395
// TypeDeprecated is a rollup condition that is present when
395396
// any of the deprecated conditions are present.
@@ -414,6 +415,8 @@ const (
414415

415416
ReasonErrorGettingReleaseState = "ErrorGettingReleaseState"
416417

418+
ReasonUnverifiable = "Unverifiable"
419+
417420
CRDUpgradeSafetyPolicyEnabled CRDUpgradeSafetyPolicy = "Enabled"
418421
CRDUpgradeSafetyPolicyDisabled CRDUpgradeSafetyPolicy = "Disabled"
419422
)
@@ -428,6 +431,7 @@ func init() {
428431
TypeChannelDeprecated,
429432
TypeBundleDeprecated,
430433
TypeUnpacked,
434+
TypeHealthy,
431435
)
432436
// TODO(user): add Reasons from above
433437
conditionsets.ConditionReasons = append(conditionsets.ConditionReasons,
@@ -441,6 +445,7 @@ func init() {
441445
ReasonUnpackSuccess,
442446
ReasonUnpackFailed,
443447
ReasonErrorGettingReleaseState,
448+
ReasonUnverifiable,
444449
)
445450
}
446451

cmd/manager/main.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,26 @@ func main() {
249249
Preflights: preflights,
250250
}
251251

252+
cm := contentmanager.NewManager(clientRestConfigMapper, mgr.GetConfig(), mgr.GetRESTMapper())
253+
contentManagerFinalizerKey := fmt.Sprintf("%s/contentmanager-cleanup", domain)
254+
err = clusterExtensionFinalizers.Register(contentManagerFinalizerKey, finalizerFunc(func(ctx context.Context, obj client.Object) (crfinalizer.Result, error) {
255+
ext := obj.(*ocv1alpha1.ClusterExtension)
256+
err := cm.Delete(ext)
257+
return crfinalizer.Result{}, err
258+
}))
259+
if err != nil {
260+
setupLog.Error(err, "unable to register content manager cleanup finalizer")
261+
os.Exit(1)
262+
}
263+
252264
if err = (&controllers.ClusterExtensionReconciler{
253265
Client: cl,
254266
Resolver: resolver,
255267
Unpacker: unpacker,
256268
Applier: applier,
257269
InstalledBundleGetter: &controllers.DefaultInstalledBundleGetter{ActionClientGetter: acg},
258270
Finalizers: clusterExtensionFinalizers,
259-
Watcher: contentmanager.New(clientRestConfigMapper, mgr.GetConfig(), mgr.GetRESTMapper()),
271+
Manager: cm,
260272
}).SetupWithManager(mgr); err != nil {
261273
setupLog.Error(err, "unable to create controller", "controller", "ClusterExtension")
262274
os.Exit(1)

config/samples/olm_v1alpha1_clusterextension.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ rules:
3636
# Manage ArgoCD CRDs
3737
- apiGroups: [apiextensions.k8s.io]
3838
resources: [customresourcedefinitions]
39-
verbs: [create]
39+
verbs: [create, list, watch]
4040
- apiGroups: [apiextensions.k8s.io]
4141
resources: [customresourcedefinitions]
42-
verbs: [get, list, watch, update, patch, delete]
42+
verbs: [get, update, patch, delete]
4343
resourceNames:
4444
- appprojects.argoproj.io
4545
- argocds.argoproj.io

internal/applier/helm.go

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
package applier
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"fmt"
8+
"io"
79
"io/fs"
810
"strings"
911

1012
"helm.sh/helm/v3/pkg/action"
1113
"helm.sh/helm/v3/pkg/chart"
1214
"helm.sh/helm/v3/pkg/chartutil"
15+
"helm.sh/helm/v3/pkg/postrender"
1316
"helm.sh/helm/v3/pkg/release"
1417
"helm.sh/helm/v3/pkg/storage/driver"
1518
corev1 "k8s.io/api/core/v1"
19+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
20+
apimachyaml "k8s.io/apimachinery/pkg/util/yaml"
1621
"sigs.k8s.io/controller-runtime/pkg/client"
1722

1823
helmclient "github.com/operator-framework/helm-operator-plugins/pkg/client"
@@ -51,7 +56,7 @@ type Helm struct {
5156
Preflights []Preflight
5257
}
5358

54-
func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1alpha1.ClusterExtension, labels map[string]string) ([]client.Object, string, error) {
59+
func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1alpha1.ClusterExtension, objectLabels map[string]string, storageLabels map[string]string) ([]client.Object, string, error) {
5560
chrt, err := convert.RegistryV1ToHelmChart(ctx, contentFS, ext.Spec.InstallNamespace, []string{corev1.NamespaceAll})
5661
if err != nil {
5762
return nil, "", err
@@ -63,7 +68,11 @@ func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1alpha1.Clust
6368
return nil, "", err
6469
}
6570

66-
rel, desiredRel, state, err := h.getReleaseState(ac, ext, chrt, values, labels)
71+
post := &postrenderer{
72+
labels: objectLabels,
73+
}
74+
75+
rel, desiredRel, state, err := h.getReleaseState(ac, ext, chrt, values, post)
6776
if err != nil {
6877
return nil, "", err
6978
}
@@ -94,18 +103,18 @@ func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1alpha1.Clust
94103
case StateNeedsInstall:
95104
rel, err = ac.Install(ext.GetName(), ext.Spec.InstallNamespace, chrt, values, func(install *action.Install) error {
96105
install.CreateNamespace = false
97-
install.Labels = labels
106+
install.Labels = storageLabels
98107
return nil
99-
})
108+
}, helmclient.AppendInstallPostRenderer(post))
100109
if err != nil {
101110
return nil, state, err
102111
}
103112
case StateNeedsUpgrade:
104113
rel, err = ac.Upgrade(ext.GetName(), ext.Spec.InstallNamespace, chrt, values, func(upgrade *action.Upgrade) error {
105114
upgrade.MaxHistory = maxHelmReleaseHistory
106-
upgrade.Labels = labels
115+
upgrade.Labels = storageLabels
107116
return nil
108-
})
117+
}, helmclient.AppendUpgradePostRenderer(post))
109118
if err != nil {
110119
return nil, state, err
111120
}
@@ -125,7 +134,7 @@ func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1alpha1.Clust
125134
return relObjects, state, nil
126135
}
127136

128-
func (h *Helm) getReleaseState(cl helmclient.ActionInterface, ext *ocv1alpha1.ClusterExtension, chrt *chart.Chart, values chartutil.Values, labels map[string]string) (*release.Release, *release.Release, string, error) {
137+
func (h *Helm) getReleaseState(cl helmclient.ActionInterface, ext *ocv1alpha1.ClusterExtension, chrt *chart.Chart, values chartutil.Values, post postrender.PostRenderer) (*release.Release, *release.Release, string, error) {
129138
currentRelease, err := cl.Get(ext.GetName())
130139
if err != nil && !errors.Is(err, driver.ErrReleaseNotFound) {
131140
return nil, nil, StateError, err
@@ -138,9 +147,8 @@ func (h *Helm) getReleaseState(cl helmclient.ActionInterface, ext *ocv1alpha1.Cl
138147
desiredRelease, err := cl.Install(ext.GetName(), ext.Spec.InstallNamespace, chrt, values, func(i *action.Install) error {
139148
i.DryRun = true
140149
i.DryRunOption = "server"
141-
i.Labels = labels
142150
return nil
143-
})
151+
}, helmclient.AppendInstallPostRenderer(post))
144152
if err != nil {
145153
return nil, nil, StateError, err
146154
}
@@ -150,9 +158,8 @@ func (h *Helm) getReleaseState(cl helmclient.ActionInterface, ext *ocv1alpha1.Cl
150158
upgrade.MaxHistory = maxHelmReleaseHistory
151159
upgrade.DryRun = true
152160
upgrade.DryRunOption = "server"
153-
upgrade.Labels = labels
154161
return nil
155-
})
162+
}, helmclient.AppendUpgradePostRenderer(post))
156163
if err != nil {
157164
return currentRelease, nil, StateError, err
158165
}
@@ -164,3 +171,33 @@ func (h *Helm) getReleaseState(cl helmclient.ActionInterface, ext *ocv1alpha1.Cl
164171
}
165172
return currentRelease, desiredRelease, relState, nil
166173
}
174+
175+
type postrenderer struct {
176+
labels map[string]string
177+
cascade postrender.PostRenderer
178+
}
179+
180+
func (p *postrenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) {
181+
var buf bytes.Buffer
182+
dec := apimachyaml.NewYAMLOrJSONDecoder(renderedManifests, 1024)
183+
for {
184+
obj := unstructured.Unstructured{}
185+
err := dec.Decode(&obj)
186+
if errors.Is(err, io.EOF) {
187+
break
188+
}
189+
if err != nil {
190+
return nil, err
191+
}
192+
obj.SetLabels(util.MergeMaps(obj.GetLabels(), p.labels))
193+
b, err := obj.MarshalJSON()
194+
if err != nil {
195+
return nil, err
196+
}
197+
buf.Write(b)
198+
}
199+
if p.cascade != nil {
200+
return p.cascade.Run(&buf)
201+
}
202+
return &buf, nil
203+
}

0 commit comments

Comments
 (0)