Skip to content

Commit e403e45

Browse files
committed
Use Helm List operator to determine Deployed status
Signed-off-by: Todd Short <tshort@redhat.com>
1 parent 6f42274 commit e403e45

File tree

9 files changed

+260
-46
lines changed

9 files changed

+260
-46
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ require (
1818
github.com/opencontainers/go-digest v1.0.0
1919
github.com/operator-framework/api v0.27.0
2020
github.com/operator-framework/catalogd v0.35.0
21-
github.com/operator-framework/helm-operator-plugins v0.5.0
21+
github.com/operator-framework/helm-operator-plugins v0.7.0
2222
github.com/operator-framework/operator-registry v1.47.0
2323
github.com/spf13/pflag v1.0.5
2424
github.com/stretchr/testify v1.9.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,8 @@ github.com/operator-framework/api v0.27.0 h1:OrVaGKZJvbZo58HTv2guz7aURkhVKYhFqZ/
537537
github.com/operator-framework/api v0.27.0/go.mod h1:lg2Xx+S8NQWGYlEOvFwQvH46E5EK5IrAIL7HWfAhciM=
538538
github.com/operator-framework/catalogd v0.35.0 h1:2lQPyHIzEfcciUjQ/fo4i/GE/sX2LBzd8S+nYxlvEHU=
539539
github.com/operator-framework/catalogd v0.35.0/go.mod h1:anZurjcFMBvbkuyqlJ98v9z+yjniPKqmhlyitk9DuBQ=
540-
github.com/operator-framework/helm-operator-plugins v0.5.0 h1:qph2OoECcI9mpuUBtOsWOMgvpx52mPTTSvzVxICsT04=
541-
github.com/operator-framework/helm-operator-plugins v0.5.0/go.mod h1:yVncrZ/FJNqedMil+055fk6sw8aMKRrget/AqGM0ig0=
540+
github.com/operator-framework/helm-operator-plugins v0.7.0 h1:YmtIWFc9BaNaDc5mk/dkG0P2BqPZOqpDvjWih5Fczuk=
541+
github.com/operator-framework/helm-operator-plugins v0.7.0/go.mod h1:fUUCJR3bWtMBZ1qdDhbwjacsBHi9uT576tF4u/DwOgQ=
542542
github.com/operator-framework/operator-lib v0.15.0 h1:0QeRM4PMtThqINpcFGCEBnIV3Z8u7/8fYLEx6mUtdcM=
543543
github.com/operator-framework/operator-lib v0.15.0/go.mod h1:ZxLvFuQ7bRWiTNBOqodbuNvcsy/Iq0kOygdxhlbNdI0=
544544
github.com/operator-framework/operator-registry v1.47.0 h1:Imr7X/W6FmXczwpIOXfnX8d6Snr1dzwWxkMG+lLAfhg=

internal/action/helm.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ func (a ActionClient) Get(name string, opts ...actionclient.GetOption) (*release
7575
return resp, err
7676
}
7777

78+
func (a ActionClient) History(name string, opts ...actionclient.HistoryOption) ([]*release.Release, error) {
79+
resp, err := a.ActionInterface.History(name, opts...)
80+
err = a.actionClientErrorTranslator(err)
81+
return resp, err
82+
}
83+
7884
func (a ActionClient) Reconcile(rel *release.Release) error {
7985
return a.actionClientErrorTranslator(a.ActionInterface.Reconcile(rel))
8086
}

internal/action/helm_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ func (m *mockActionClient) Get(name string, opts ...actionclient.GetOption) (*re
3030
return args.Get(0).(*release.Release), args.Error(1)
3131
}
3232

33+
func (m *mockActionClient) History(name string, opts ...actionclient.HistoryOption) ([]*release.Release, error) {
34+
args := m.Called(name, opts)
35+
if args.Get(0) == nil {
36+
return nil, args.Error(1)
37+
}
38+
rel := []*release.Release{
39+
args.Get(0).(*release.Release),
40+
}
41+
return rel, args.Error(1)
42+
}
43+
3344
func (m *mockActionClient) Install(name, namespace string, chrt *chart.Chart, vals map[string]interface{}, opts ...actionclient.InstallOption) (*release.Release, error) {
3445
args := m.Called(name, namespace, chrt, vals, opts)
3546
if args.Get(0) == nil {
@@ -82,6 +93,7 @@ func TestActionClientErrorTranslation(t *testing.T) {
8293

8394
ac := new(mockActionClient)
8495
ac.On("Get", mock.Anything, mock.Anything).Return(nil, originalError)
96+
ac.On("History", mock.Anything, mock.Anything).Return(nil, originalError)
8597
ac.On("Install", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, originalError)
8698
ac.On("Uninstall", mock.Anything, mock.Anything).Return(nil, originalError)
8799
ac.On("Upgrade", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, originalError)
@@ -93,6 +105,10 @@ func TestActionClientErrorTranslation(t *testing.T) {
93105
_, err := wrappedAc.Get("something")
94106
assert.Equal(t, expectedErr, err, "expected Get() to return translated error")
95107

108+
// History
109+
_, err = wrappedAc.History("something")
110+
assert.Equal(t, expectedErr, err, "expected History() to return translated error")
111+
96112
// Install
97113
_, err = wrappedAc.Install("something", "somethingelse", nil, nil)
98114
assert.Equal(t, expectedErr, err, "expected Install() to return translated error")

internal/controllers/clusterextension_controller.go

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ type Applier interface {
8484
}
8585

8686
type InstalledBundleGetter interface {
87-
GetInstalledBundle(ctx context.Context, ext *ocv1alpha1.ClusterExtension) (*ocv1alpha1.BundleMetadata, error)
87+
GetInstalledBundle(ctx context.Context, ext *ocv1alpha1.ClusterExtension) (*InstalledBundle, error)
8888
}
8989

9090
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterextensions,verbs=get;list;watch;update;patch
@@ -206,19 +206,22 @@ func (r *ClusterExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alp
206206
installedBundle, err := r.InstalledBundleGetter.GetInstalledBundle(ctx, ext)
207207
if err != nil {
208208
setInstallStatus(ext, nil)
209-
// TODO: use Installed=Unknown
210-
setInstalledStatusConditionFailed(ext, err.Error())
211-
setStatusProgressing(ext, err)
209+
setInstalledStatusConditionUnknown(ext, err.Error())
210+
setStatusProgressing(ext, errors.New("retrying to get installed bundle"))
212211
return ctrl.Result{}, err
213212
}
214213

215214
// run resolution
216215
l.Info("resolving bundle")
217-
resolvedBundle, resolvedBundleVersion, resolvedDeprecation, err := r.Resolver.Resolve(ctx, ext, installedBundle)
216+
var bm *ocv1alpha1.BundleMetadata
217+
if installedBundle != nil {
218+
bm = &installedBundle.BundleMetadata
219+
}
220+
resolvedBundle, resolvedBundleVersion, resolvedDeprecation, err := r.Resolver.Resolve(ctx, ext, bm)
218221
if err != nil {
219222
// Note: We don't distinguish between resolution-specific errors and generic errors
220-
setInstallStatus(ext, nil)
221223
setStatusProgressing(ext, err)
224+
setInstalledStatusFromBundle(ext, installedBundle, nil)
222225
ensureAllConditionsWithReason(ext, ocv1alpha1.ReasonFailed, err.Error())
223226
return ctrl.Result{}, err
224227
}
@@ -255,6 +258,7 @@ func (r *ClusterExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alp
255258
// installed since we intend for the progressing condition to replace the resolved condition
256259
// and will be removing the .status.resolution field from the ClusterExtension status API
257260
setStatusProgressing(ext, wrapErrorWithResolutionInfo(resolvedBundleMetadata, err))
261+
setInstalledStatusFromBundle(ext, installedBundle, nil)
258262
return ctrl.Result{}, err
259263
}
260264

@@ -268,9 +272,10 @@ func (r *ClusterExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alp
268272
}
269273

270274
storeLbls := map[string]string{
271-
labels.BundleNameKey: resolvedBundle.Name,
272-
labels.PackageNameKey: resolvedBundle.Package,
273-
labels.BundleVersionKey: resolvedBundleVersion.String(),
275+
labels.BundleNameKey: resolvedBundle.Name,
276+
labels.PackageNameKey: resolvedBundle.Package,
277+
labels.BundleVersionKey: resolvedBundleVersion.String(),
278+
labels.BundleReferenceKey: resolvedBundle.Image,
274279
}
275280

276281
l.Info("applying bundle contents")
@@ -286,18 +291,17 @@ func (r *ClusterExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alp
286291
managedObjs, _, err := r.Applier.Apply(ctx, unpackResult.Bundle, ext, objLbls, storeLbls)
287292
if err != nil {
288293
setStatusProgressing(ext, wrapErrorWithResolutionInfo(resolvedBundleMetadata, err))
289-
// If bundle is not already installed, set Installed status condition to False
290-
if installedBundle == nil {
291-
setInstalledStatusConditionFailed(ext, err.Error())
292-
}
294+
// Now that we're actually trying to install, use the error
295+
setInstalledStatusFromBundle(ext, installedBundle, err)
293296
return ctrl.Result{}, err
294297
}
295298

296-
installStatus := &ocv1alpha1.ClusterExtensionInstallStatus{
297-
Bundle: resolvedBundleMetadata,
299+
newInstalledBundle := &InstalledBundle{
300+
BundleMetadata: resolvedBundleMetadata,
301+
Image: resolvedBundle.Image,
298302
}
299-
setInstallStatus(ext, installStatus)
300-
setInstalledStatusConditionSuccess(ext, fmt.Sprintf("Installed bundle %s successfully", resolvedBundle.Image))
303+
// Successful install
304+
setInstalledStatusFromBundle(ext, newInstalledBundle, nil)
301305

302306
l.Info("watching managed objects")
303307
cache, err := r.Manager.Get(ctx, ext)
@@ -466,32 +470,46 @@ type DefaultInstalledBundleGetter struct {
466470
helmclient.ActionClientGetter
467471
}
468472

469-
func (d *DefaultInstalledBundleGetter) GetInstalledBundle(ctx context.Context, ext *ocv1alpha1.ClusterExtension) (*ocv1alpha1.BundleMetadata, error) {
473+
type InstalledBundle struct {
474+
ocv1alpha1.BundleMetadata
475+
Image string
476+
}
477+
478+
func (d *DefaultInstalledBundleGetter) GetInstalledBundle(ctx context.Context, ext *ocv1alpha1.ClusterExtension) (*InstalledBundle, error) {
470479
cl, err := d.ActionClientFor(ctx, ext)
471480
if err != nil {
472481
return nil, err
473482
}
474483

475-
rel, err := cl.Get(ext.GetName())
484+
relhis, err := cl.History(ext.GetName())
476485
if err != nil && !errors.Is(err, driver.ErrReleaseNotFound) {
477486
return nil, err
478487
}
479-
if rel == nil {
488+
if len(relhis) == 0 {
480489
return nil, nil
481490
}
482491

483-
switch rel.Info.Status {
484-
case release.StatusUnknown:
485-
return nil, fmt.Errorf("installation status is unknown")
486-
case release.StatusDeployed, release.StatusUninstalled, release.StatusSuperseded, release.StatusFailed:
487-
case release.StatusUninstalling, release.StatusPendingInstall, release.StatusPendingRollback, release.StatusPendingUpgrade:
488-
return nil, fmt.Errorf("installation is still pending: %s", rel.Info.Status)
489-
default:
490-
return nil, fmt.Errorf("unknown installation status: %s", rel.Info.Status)
492+
// TODO: relhis[0].Info.Status is the status of the most recent install attempt.
493+
// This might be useful informaton if it's not release.StatusDeployed, in telling us
494+
// the status of an upgrade attempt.
495+
for _, rel := range relhis {
496+
if rel.Info != nil && rel.Info.Status == release.StatusDeployed {
497+
// If there are blank values, we should consider this as not installed
498+
if n, ok := rel.Labels[labels.BundleNameKey]; !ok || n == "" {
499+
return nil, nil
500+
}
501+
if v, ok := rel.Labels[labels.BundleVersionKey]; !ok || v == "" {
502+
return nil, nil
503+
}
504+
// Not checking BundleReferenceKey, as it's new; upgrade test would fail
505+
return &InstalledBundle{
506+
BundleMetadata: ocv1alpha1.BundleMetadata{
507+
Name: rel.Labels[labels.BundleNameKey],
508+
Version: rel.Labels[labels.BundleVersionKey],
509+
},
510+
Image: rel.Labels[labels.BundleReferenceKey],
511+
}, nil
512+
}
491513
}
492-
493-
return &ocv1alpha1.BundleMetadata{
494-
Name: rel.Labels[labels.BundleNameKey],
495-
Version: rel.Labels[labels.BundleVersionKey],
496-
}, nil
514+
return nil, nil
497515
}

0 commit comments

Comments
 (0)