Skip to content

Commit 6094188

Browse files
Merge pull request #388 from openshift-cherrypick-robot/cherry-pick-360-to-release-4.11
[release-4.11] OCPBUGS-1556: Cleanup conversion webhooks when an operator is uninstalled
2 parents 6462512 + eb07e3c commit 6094188

File tree

4 files changed

+106
-1
lines changed

4 files changed

+106
-1
lines changed

staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
1212
corev1 "k8s.io/api/core/v1"
1313
rbacv1 "k8s.io/api/rbac/v1"
14+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1415
extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions"
1516
apierrors "k8s.io/apimachinery/pkg/api/errors"
1617
"k8s.io/apimachinery/pkg/api/meta"
@@ -1119,6 +1120,46 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) {
11191120
logger.WithError(err).Warnf("failed to requeue gc event: %v", webhook)
11201121
}
11211122
}
1123+
1124+
// Conversion webhooks are defined within a CRD.
1125+
// In an effort to prevent customer dataloss, OLM does not delete CRDs associated with a CSV when it is deleted.
1126+
// Deleting a CSV that introduced a conversion webhook removes the deployment that serviced the conversion webhook calls.
1127+
// If a conversion webhook is defined and the service isn't available, all requests against the CR associated with the CRD will fail.
1128+
// This ultimately breaks kubernetes garbage collection and prevents OLM from reinstalling the CSV as CR validation against the new CRD's
1129+
// openapiv3 schema fails.
1130+
// As such, when a CSV is deleted OLM will check if it is being replaced. If the CSV is not being replaced, OLM will remove the conversion
1131+
// webhook from the CRD definition.
1132+
csvs, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(clusterServiceVersion.GetNamespace()).List(labels.Everything())
1133+
if err != nil {
1134+
logger.Errorf("error listing csvs: %v\n", err)
1135+
}
1136+
for _, csv := range csvs {
1137+
if csv.Spec.Replaces == clusterServiceVersion.GetName() {
1138+
return
1139+
}
1140+
}
1141+
1142+
for _, desc := range clusterServiceVersion.Spec.WebhookDefinitions {
1143+
if desc.Type != v1alpha1.ConversionWebhook || len(desc.ConversionCRDs) == 0 {
1144+
continue
1145+
}
1146+
1147+
for i, crdName := range desc.ConversionCRDs {
1148+
crd, err := a.lister.APIExtensionsV1().CustomResourceDefinitionLister().Get(crdName)
1149+
if err != nil {
1150+
logger.Errorf("error getting CRD %v which was defined in CSVs spec.WebhookDefinition[%d]: %v\n", crdName, i, err)
1151+
continue
1152+
}
1153+
1154+
copy := crd.DeepCopy()
1155+
copy.Spec.Conversion.Strategy = apiextensionsv1.NoneConverter
1156+
copy.Spec.Conversion.Webhook = nil
1157+
1158+
if _, err = a.opClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), copy, metav1.UpdateOptions{}); err != nil {
1159+
logger.Errorf("error updating conversion strategy for CRD %v: %v\n", crdName, err)
1160+
}
1161+
}
1162+
}
11221163
}
11231164

11241165
func (a *Operator) removeDanglingChildCSVs(csv *v1alpha1.ClusterServiceVersion) error {

staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4206,6 +4206,9 @@ func findLastEvent(events *corev1.EventList) (event corev1.Event) {
42064206
func buildCSVCleanupFunc(c operatorclient.ClientInterface, crc versioned.Interface, csv operatorsv1alpha1.ClusterServiceVersion, namespace string, deleteCRDs, deleteAPIServices bool) cleanupFunc {
42074207
return func() {
42084208
err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace).Delete(context.TODO(), csv.GetName(), metav1.DeleteOptions{})
4209+
if err != nil && apierrors.IsNotFound(err) {
4210+
err = nil
4211+
}
42094212
Expect(err).ShouldNot(HaveOccurred())
42104213

42114214
if deleteCRDs {

staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ var _ = Describe("CSVs with a Webhook", func() {
639639
}).Should(Equal(2))
640640
})
641641
When("Installed from a catalog Source", func() {
642+
const csvName = "webhook-operator.v0.0.1"
642643
var cleanupCSV cleanupFunc
643644
var cleanupCatSrc cleanupFunc
644645
var cleanupSubscription cleanupFunc
@@ -687,7 +688,7 @@ var _ = Describe("CSVs with a Webhook", func() {
687688
defer cleanupSubscription()
688689

689690
// Wait for webhook-operator v2 csv to succeed
690-
csv, err := awaitCSV(crc, source.GetNamespace(), "webhook-operator.v0.0.1", csvSucceededChecker)
691+
csv, err := awaitCSV(crc, source.GetNamespace(), csvName, csvSucceededChecker)
691692
require.NoError(GinkgoT(), err)
692693

693694
cleanupCSV = buildCSVCleanupFunc(c, crc, *csv, source.GetNamespace(), true, true)
@@ -775,6 +776,25 @@ var _ = Describe("CSVs with a Webhook", func() {
775776
require.True(GinkgoT(), ok, "Unable to get spec.conversion.valid of v2 object")
776777
require.True(GinkgoT(), v2SpecConversionMutate)
777778
require.True(GinkgoT(), v2SpecConversionValid)
779+
780+
// Check that conversion strategies are disabled after uninstalling the operator.
781+
err = crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Delete(context.TODO(), csvName, metav1.DeleteOptions{})
782+
require.NoError(GinkgoT(), err)
783+
784+
Eventually(func() error {
785+
crd, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), "webhooktests.webhook.operators.coreos.io", metav1.GetOptions{})
786+
if err != nil {
787+
return err
788+
}
789+
790+
if crd.Spec.Conversion.Strategy != apiextensionsv1.NoneConverter {
791+
return fmt.Errorf("conversion strategy is not NoneConverter")
792+
}
793+
if crd.Spec.Conversion.Webhook != nil {
794+
return fmt.Errorf("webhook is not nil")
795+
}
796+
return nil
797+
}).Should(Succeed())
778798
})
779799
})
780800
When("WebhookDescription has conversionCRDs field", func() {

vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go

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

0 commit comments

Comments
 (0)