Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/v1/clusterextensionrevision_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
ClusterExtensionRevisionReasonProbeFailure = "ProbeFailure"
ClusterExtensionRevisionReasonIncomplete = "Incomplete"
ClusterExtensionRevisionReasonProgressing = "Progressing"
ClusterExtensionRevisionReasonArchived = "Archived"
)

// ClusterExtensionRevisionSpec defines the desired state of ClusterExtensionRevision.
Expand Down Expand Up @@ -148,6 +149,8 @@ type ClusterExtensionRevisionStatus struct {
// +kubebuilder:subresource:status

// ClusterExtensionRevision is the Schema for the clusterextensionrevisions API
// +kubebuilder:printcolumn:name="Available",type=string,JSONPath=`.status.conditions[?(@.type=='Available')].status`
// +kubebuilder:printcolumn:name=Age,type=date,JSONPath=`.metadata.creationTimestamp`
type ClusterExtensionRevision struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ spec:
singular: clusterextensionrevision
scope: Cluster
versions:
- name: v1
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Available')].status
name: Available
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: ClusterExtensionRevision is the Schema for the clusterextensionrevisions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,52 +118,8 @@ func (c *ClusterExtensionRevisionReconciler) reconcile(ctx context.Context, rev

revision, opts, previous := toBoxcutterRevision(rev)

if !rev.DeletionTimestamp.IsZero() ||
rev.Spec.LifecycleState == ocv1.ClusterExtensionRevisionLifecycleStateArchived {
//
// Teardown
//
tres, err := c.RevisionEngine.Teardown(ctx, *revision)
if err != nil {
meta.SetStatusCondition(&rev.Status.Conditions, metav1.Condition{
Type: ocv1.ClusterExtensionRevisionTypeAvailable,
Status: metav1.ConditionFalse,
Reason: ocv1.ClusterExtensionRevisionReasonReconcileFailure,
Message: err.Error(),
ObservedGeneration: rev.Generation,
})
return ctrl.Result{}, fmt.Errorf("revision teardown: %v", err)
}

l.Info("teardown report", "report", tres.String())
if !tres.IsComplete() {
// TODO: If it is not complete, it seems like it would be good to update
// the status in some way to tell the user that the teardown is still
// in progress.
return ctrl.Result{}, nil
}

if err := c.TrackingCache.Free(ctx, rev); err != nil {
meta.SetStatusCondition(&rev.Status.Conditions, metav1.Condition{
Type: ocv1.ClusterExtensionRevisionTypeAvailable,
Status: metav1.ConditionFalse,
Reason: ocv1.ClusterExtensionRevisionReasonReconcileFailure,
Message: err.Error(),
ObservedGeneration: rev.Generation,
})
return ctrl.Result{}, fmt.Errorf("error stopping informers: %v", err)
}
if err := c.removeFinalizer(ctx, rev, clusterExtensionRevisionTeardownFinalizer); err != nil {
meta.SetStatusCondition(&rev.Status.Conditions, metav1.Condition{
Type: "Available",
Status: metav1.ConditionFalse,
Reason: "ReconcileFailure",
Message: err.Error(),
ObservedGeneration: rev.Generation,
})
return ctrl.Result{}, fmt.Errorf("error removing teardown finalizer: %v", err)
}
return ctrl.Result{}, nil
if !rev.DeletionTimestamp.IsZero() || rev.Spec.LifecycleState == ocv1.ClusterExtensionRevisionLifecycleStateArchived {
return c.teardown(ctx, rev, revision)
}

//
Expand Down Expand Up @@ -339,6 +295,59 @@ func (c *ClusterExtensionRevisionReconciler) reconcile(ctx context.Context, rev
return ctrl.Result{}, nil
}

func (c *ClusterExtensionRevisionReconciler) teardown(ctx context.Context, rev *ocv1.ClusterExtensionRevision, revision *boxcutter.Revision) (ctrl.Result, error) {
l := log.FromContext(ctx)

tres, err := c.RevisionEngine.Teardown(ctx, *revision)
if err != nil {
meta.SetStatusCondition(&rev.Status.Conditions, metav1.Condition{
Type: ocv1.ClusterExtensionRevisionTypeAvailable,
Status: metav1.ConditionFalse,
Reason: ocv1.ClusterExtensionRevisionReasonReconcileFailure,
Message: err.Error(),
ObservedGeneration: rev.Generation,
})
return ctrl.Result{}, fmt.Errorf("revision teardown: %v", err)
}

l.Info("teardown report", "report", tres.String())
if !tres.IsComplete() {
// TODO: If it is not complete, it seems like it would be good to update
// the status in some way to tell the user that the teardown is still
// in progress.
return ctrl.Result{}, nil
}

if err := c.TrackingCache.Free(ctx, rev); err != nil {
meta.SetStatusCondition(&rev.Status.Conditions, metav1.Condition{
Type: ocv1.ClusterExtensionRevisionTypeAvailable,
Status: metav1.ConditionFalse,
Reason: ocv1.ClusterExtensionRevisionReasonReconcileFailure,
Message: err.Error(),
ObservedGeneration: rev.Generation,
})
return ctrl.Result{}, fmt.Errorf("error stopping informers: %v", err)
}

// Ensure Available condition is set to Unknown before removing the finalizer when archiving
if rev.Spec.LifecycleState == ocv1.ClusterExtensionRevisionLifecycleStateArchived &&
!meta.IsStatusConditionPresentAndEqual(rev.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable, metav1.ConditionUnknown) {
meta.SetStatusCondition(&rev.Status.Conditions, metav1.Condition{
Type: ocv1.ClusterExtensionRevisionTypeAvailable,
Status: metav1.ConditionUnknown,
Reason: ocv1.ClusterExtensionRevisionReasonArchived,
Message: "revision is archived",
ObservedGeneration: rev.Generation,
})
return ctrl.Result{}, nil
}

if err := c.removeFinalizer(ctx, rev, clusterExtensionRevisionTeardownFinalizer); err != nil {
return ctrl.Result{}, fmt.Errorf("error removing teardown finalizer: %v", err)
}
return ctrl.Result{}, nil
}

type Sourcerer interface {
Source(handler handler.EventHandler, predicates ...predicate.Predicate) source.Source
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,40 @@ func Test_ClusterExtensionRevisionReconciler_Reconcile_Deletion(t *testing.T) {
require.NotContains(t, "olm.operatorframework.io/teardown", rev.Finalizers)
},
},
{
name: "set Available condition to Unknown with reason Archived when archiving revision",
revisionResult: mockRevisionResult{},
existingObjs: func() []client.Object {
ext := newTestClusterExtension()
rev1 := newTestClusterExtensionRevision(clusterExtensionRevisionName)
rev1.Finalizers = []string{
"olm.operatorframework.io/teardown",
}
rev1.Spec.LifecycleState = ocv1.ClusterExtensionRevisionLifecycleStateArchived
require.NoError(t, controllerutil.SetControllerReference(ext, rev1, testScheme))
return []client.Object{rev1, ext}
},
revisionEngineTeardownFn: func(t *testing.T) func(ctx context.Context, rev machinerytypes.Revision, opts ...machinerytypes.RevisionTeardownOption) (machinery.RevisionTeardownResult, error) {
return func(ctx context.Context, rev machinerytypes.Revision, opts ...machinerytypes.RevisionTeardownOption) (machinery.RevisionTeardownResult, error) {
return &mockRevisionTeardownResult{
isComplete: true,
}, nil
}
},
validate: func(t *testing.T, c client.Client) {
rev := &ocv1.ClusterExtensionRevision{}
err := c.Get(t.Context(), client.ObjectKey{
Name: clusterExtensionRevisionName,
}, rev)
require.NoError(t, err)
cond := meta.FindStatusCondition(rev.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
require.NotNil(t, cond)
require.Equal(t, metav1.ConditionUnknown, cond.Status)
require.Equal(t, ocv1.ClusterExtensionRevisionReasonArchived, cond.Reason)
require.Equal(t, "revision is archived", cond.Message)
require.Equal(t, int64(1), cond.ObservedGeneration)
},
},
{
name: "revision is torn down when in archived state and finalizer is removed",
revisionResult: mockRevisionResult{},
Expand All @@ -554,6 +588,13 @@ func Test_ClusterExtensionRevisionReconciler_Reconcile_Deletion(t *testing.T) {
"olm.operatorframework.io/teardown",
}
rev1.Spec.LifecycleState = ocv1.ClusterExtensionRevisionLifecycleStateArchived
meta.SetStatusCondition(&rev1.Status.Conditions, metav1.Condition{
Type: ocv1.ClusterExtensionRevisionTypeAvailable,
Status: metav1.ConditionUnknown,
Reason: ocv1.ClusterExtensionRevisionReasonArchived,
Message: "revision is archived",
ObservedGeneration: rev1.Generation,
})
require.NoError(t, controllerutil.SetControllerReference(ext, rev1, testScheme))
return []client.Object{rev1, ext}
},
Expand All @@ -570,7 +611,7 @@ func Test_ClusterExtensionRevisionReconciler_Reconcile_Deletion(t *testing.T) {
Name: clusterExtensionRevisionName,
}, rev)
require.NoError(t, err)
require.NotContains(t, "olm.operatorframework.io/teardown", rev.Finalizers)
require.NotContains(t, rev.Finalizers, "olm.operatorframework.io/teardown")
},
},
{
Expand Down
9 changes: 8 additions & 1 deletion manifests/experimental-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,14 @@ spec:
singular: clusterextensionrevision
scope: Cluster
versions:
- name: v1
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Available')].status
name: Available
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: ClusterExtensionRevision is the Schema for the clusterextensionrevisions
Expand Down
9 changes: 8 additions & 1 deletion manifests/experimental.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,14 @@ spec:
singular: clusterextensionrevision
scope: Cluster
versions:
- name: v1
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Available')].status
name: Available
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: ClusterExtensionRevision is the Schema for the clusterextensionrevisions
Expand Down
Loading