Skip to content

Commit fc6550c

Browse files
Merge pull request openshift#670 from kevinrizza/backport-e2es
[release-4.15] OCPBUGS-25798: Fix snapshot failure, backport e2es
2 parents b66c669 + 2b9b74f commit fc6550c

File tree

6 files changed

+114
-54
lines changed

6 files changed

+114
-54
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
346346
subscription.WithAppendedReconcilers(subscription.ReconcilerFromLegacySyncHandler(op.syncSubscriptions, nil)),
347347
subscription.WithRegistryReconcilerFactory(op.reconciler),
348348
subscription.WithGlobalCatalogNamespace(op.namespace),
349-
subscription.WithSourceProvider(resolverSourceProvider),
349+
subscription.WithSourceProvider(op.sourceInvalidator),
350350
)
351351
if err != nil {
352352
return nil, err

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -4441,6 +4441,7 @@ func fetchCSV(c versioned.Interface, namespace, name string, checker csvConditio
44414441
var lastPhase operatorsv1alpha1.ClusterServiceVersionPhase
44424442
var lastReason operatorsv1alpha1.ConditionReason
44434443
var lastMessage string
4444+
var lastError string
44444445
lastTime := time.Now()
44454446
var csv *operatorsv1alpha1.ClusterServiceVersion
44464447

@@ -4449,7 +4450,10 @@ func fetchCSV(c versioned.Interface, namespace, name string, checker csvConditio
44494450
var err error
44504451
csv, err = c.OperatorsV1alpha1().ClusterServiceVersions(namespace).Get(context.TODO(), name, metav1.GetOptions{})
44514452
if err != nil || csv == nil {
4452-
ctx.Ctx().Logf("error getting csv %s/%s: %v", namespace, name, err)
4453+
if lastError != err.Error() {
4454+
ctx.Ctx().Logf("error getting csv %s/%s: %v", namespace, name, err)
4455+
lastError = err.Error()
4456+
}
44534457
return false, nil
44544458
}
44554459
phase, reason, message := csv.Status.Phase, csv.Status.Reason, csv.Status.Message

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

+36-12
Original file line numberDiff line numberDiff line change
@@ -2792,10 +2792,13 @@ var _ = Describe("Install Plan", func() {
27922792
_, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, generatedNamespace.GetName(), catalogSourceRegistryPodSynced())
27932793
require.NoError(GinkgoT(), err)
27942794

2795+
By("Creating a Subscription")
27952796
subscriptionName := genName("sub-nginx-")
2796-
subscriptionCleanup := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subscriptionName, mainCatalogSourceName, packageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic)
2797-
defer subscriptionCleanup()
2797+
// Subscription is explitly deleted as part of the test to avoid CSV being recreated,
2798+
// so ignore cleanup function
2799+
_ = createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subscriptionName, mainCatalogSourceName, packageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic)
27982800

2801+
By("Attempt to get Subscription")
27992802
subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker())
28002803
require.NoError(GinkgoT(), err)
28012804
require.NotNil(GinkgoT(), subscription)
@@ -2867,22 +2870,38 @@ var _ = Describe("Install Plan", func() {
28672870
By("Should have removed every matching step")
28682871
require.Equal(GinkgoT(), 0, len(expectedSteps), "Actual resource steps do not match expected: %#v", expectedSteps)
28692872

2870-
GinkgoT().Logf("deleting csv %s/%s", generatedNamespace.GetName(), stableCSVName)
2871-
By("Explicitly delete the CSV")
2872-
err = crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Delete(context.Background(), stableCSVName, metav1.DeleteOptions{})
2873+
By(fmt.Sprintf("Explicitly deleting subscription %s/%s", generatedNamespace.GetName(), subscriptionName))
2874+
err = crc.OperatorsV1alpha1().Subscriptions(generatedNamespace.GetName()).Delete(context.Background(), subscriptionName, metav1.DeleteOptions{})
28732875
By("Looking for no error OR IsNotFound error")
2874-
if err != nil && apierrors.IsNotFound(err) {
2875-
err = nil
2876-
}
2877-
require.NoError(GinkgoT(), err)
2876+
require.NoError(GinkgoT(), client.IgnoreNotFound(err))
2877+
2878+
By("Waiting for the Subscription to delete")
2879+
err = waitForSubscriptionToDelete(generatedNamespace.GetName(), subscriptionName, crc)
2880+
require.NoError(GinkgoT(), client.IgnoreNotFound(err))
28782881

2882+
By(fmt.Sprintf("Explicitly deleting csv %s/%s", generatedNamespace.GetName(), stableCSVName))
2883+
err = crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Delete(context.Background(), stableCSVName, metav1.DeleteOptions{})
2884+
By("Looking for no error OR IsNotFound error")
2885+
require.NoError(GinkgoT(), client.IgnoreNotFound(err))
2886+
By("Waiting for the CSV to delete")
2887+
err = waitForCsvToDelete(generatedNamespace.GetName(), stableCSVName, crc)
2888+
require.NoError(GinkgoT(), client.IgnoreNotFound(err))
2889+
2890+
nCrs := 0
2891+
nCrbs := 0
2892+
By("Waiting for CRBs and CRs and SAs to delete")
28792893
Eventually(func() bool {
2894+
28802895
crbs, err := c.KubernetesInterface().RbacV1().ClusterRoleBindings().List(context.Background(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)})
28812896
if err != nil {
28822897
GinkgoT().Logf("error getting crbs: %v", err)
28832898
return false
28842899
}
2885-
if len(crbs.Items) != 0 {
2900+
if n := len(crbs.Items); n != 0 {
2901+
if n != nCrbs {
2902+
GinkgoT().Logf("CRBs remaining: %v", n)
2903+
nCrbs = n
2904+
}
28862905
return false
28872906
}
28882907

@@ -2891,18 +2910,23 @@ var _ = Describe("Install Plan", func() {
28912910
GinkgoT().Logf("error getting crs: %v", err)
28922911
return false
28932912
}
2894-
if len(crs.Items) != 0 {
2913+
if n := len(crs.Items); n != 0 {
2914+
if n != nCrs {
2915+
GinkgoT().Logf("CRs remaining: %v", n)
2916+
nCrs = n
2917+
}
28952918
return false
28962919
}
28972920

28982921
_, err = c.KubernetesInterface().CoreV1().ServiceAccounts(generatedNamespace.GetName()).Get(context.Background(), serviceAccountName, metav1.GetOptions{})
2899-
if err != nil && !apierrors.IsNotFound(err) {
2922+
if client.IgnoreNotFound(err) != nil {
29002923
GinkgoT().Logf("error getting sa %s/%s: %v", generatedNamespace.GetName(), serviceAccountName, err)
29012924
return false
29022925
}
29032926

29042927
return true
29052928
}, pollDuration*2, pollInterval).Should(BeTrue())
2929+
By("Cleaning up the test")
29062930
})
29072931

29082932
It("CRD validation", func() {

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

+69-39
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import (
3838
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
3939
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
4040
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/projection"
41-
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/comparison"
4241
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
4342
"github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx"
4443
registryapi "github.com/operator-framework/operator-registry/pkg/api"
@@ -328,7 +327,7 @@ var _ = Describe("Subscription", func() {
328327
subscriptionCleanup, _ := createSubscription(GinkgoT(), crc, generatedNamespace.GetName(), "manual-subscription", testPackageName, stableChannel, operatorsv1alpha1.ApprovalManual)
329328
defer subscriptionCleanup()
330329

331-
subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), "manual-subscription", subscriptionStateUpgradePendingChecker())
330+
subscription, err := fetchSubscription(crc, generatedNamespace.GetName(), "manual-subscription", subscriptionHasCondition(operatorsv1alpha1.SubscriptionInstallPlanPending, corev1.ConditionTrue, string(operatorsv1alpha1.InstallPlanPhaseRequiresApproval), ""))
332331
require.NoError(GinkgoT(), err)
333332
require.NotNil(GinkgoT(), subscription)
334333

@@ -1029,29 +1028,7 @@ var _ = Describe("Subscription", func() {
10291028
})
10301029

10311030
It("can reconcile InstallPlan status", func() {
1032-
By(`TestSubscriptionInstallPlanStatus ensures that a Subscription has the appropriate status conditions for possible referenced`)
1033-
By(`InstallPlan states.`)
1034-
By(` BySteps:`)
1035-
By(`- Utilize the namespace and OG targeting that namespace created in the BeforeEach clause`)
1036-
By(`- Create CatalogSource, cs, in ns`)
1037-
By(`- Create Subscription to a package of cs in ns, sub`)
1038-
By(`- Wait for the package from sub to install successfully with no remaining InstallPlan status conditions`)
1039-
By(`- Store conditions for later comparision`)
1040-
By(`- Get the InstallPlan`)
1041-
By(`- Set the InstallPlan's approval mode to Manual`)
1042-
By(`- Set the InstallPlan's phase to None`)
1043-
By(`- Wait for sub to have status condition SubscriptionInstallPlanPending true and reason InstallPlanNotYetReconciled`)
1044-
By(`- Get the latest IntallPlan and set the phase to InstallPlanPhaseRequiresApproval`)
1045-
By(`- Wait for sub to have status condition SubscriptionInstallPlanPending true and reason RequiresApproval`)
1046-
By(`- Get the latest InstallPlan and set the phase to InstallPlanPhaseInstalling`)
1047-
By(`- Wait for sub to have status condition SubscriptionInstallPlanPending true and reason Installing`)
1048-
By(`- Get the latest InstallPlan and set the phase to InstallPlanPhaseFailed and remove all status conditions`)
1049-
By(`- Wait for sub to have status condition SubscriptionInstallPlanFailed true and reason InstallPlanFailed`)
1050-
By(`- Get the latest InstallPlan and set status condition of type Installed to false with reason InstallComponentFailed`)
1051-
By(`- Wait for sub to have status condition SubscriptionInstallPlanFailed true and reason InstallComponentFailed`)
1052-
By(`- Delete the referenced InstallPlan`)
1053-
By(`- Wait for sub to have status condition SubscriptionInstallPlanMissing true`)
1054-
By(`- Ensure original non-InstallPlan status conditions remain after InstallPlan transitions`)
1031+
By(`TestSubscriptionInstallPlanStatus ensures that a Subscription has the appropriate status conditions for possible referenced InstallPlan states.`)
10551032
c := newKubeClient()
10561033
crc := newCRClient()
10571034

@@ -1099,6 +1076,7 @@ var _ = Describe("Subscription", func() {
10991076
ref := sub.Status.InstallPlanRef
11001077
Expect(ref).ToNot(BeNil())
11011078

1079+
By(`Get the InstallPlan`)
11021080
plan := &operatorsv1alpha1.InstallPlan{}
11031081
plan.SetNamespace(ref.Namespace)
11041082
plan.SetName(ref.Name)
@@ -1151,14 +1129,14 @@ var _ = Describe("Subscription", func() {
11511129
return true
11521130
}
11531131

1154-
By(`Sometimes the transition from installing to complete can be so quick that the test does not capture`)
1155-
By(`the condition in the subscription before it is removed. To mitigate this, we check if the installplan`)
1156-
By(`has transitioned to complete and exit out the fetch subscription loop if so.`)
1157-
By(`This is a mitigation. We should probably fix this test appropriately.`)
1158-
By(`issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2667`)
1132+
// Sometimes the transition from installing to complete can be so quick that the test does not capture
1133+
// the condition in the subscription before it is removed. To mitigate this, we check if the installplan
1134+
// has transitioned to complete and exit out the fetch subscription loop if so.
1135+
// This is a mitigation. We should probably fix this test appropriately.
1136+
// issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2667
11591137
ip, err := crc.OperatorsV1alpha1().InstallPlans(generatedNamespace.GetName()).Get(context.TODO(), plan.Name, metav1.GetOptions{})
11601138
if err != nil {
1161-
By(`retry on failure`)
1139+
// retry on failure
11621140
return false
11631141
}
11641142
isInstallPlanComplete := ip.Status.Phase == operatorsv1alpha1.InstallPlanPhaseComplete
@@ -1210,16 +1188,13 @@ var _ = Describe("Subscription", func() {
12101188
Expect(err).ToNot(HaveOccurred())
12111189
Expect(sub).ToNot(BeNil())
12121190

1213-
By(`Ensure original non-InstallPlan status conditions remain after InstallPlan transitions`)
1214-
hashEqual := comparison.NewHashEqualitor()
1191+
By(`Ensure InstallPlan-related status conditions match what we're expecting`)
12151192
for _, cond := range conds {
12161193
switch condType := cond.Type; condType {
12171194
case operatorsv1alpha1.SubscriptionInstallPlanPending, operatorsv1alpha1.SubscriptionInstallPlanFailed:
12181195
require.FailNowf(GinkgoT(), "failed", "subscription contains unexpected installplan condition: %v", cond)
12191196
case operatorsv1alpha1.SubscriptionInstallPlanMissing:
12201197
require.Equal(GinkgoT(), operatorsv1alpha1.ReferencedInstallPlanNotFound, cond.Reason)
1221-
default:
1222-
require.True(GinkgoT(), hashEqual(cond, sub.Status.GetCondition(condType)), "non-installplan status condition changed")
12231198
}
12241199
}
12251200
})
@@ -3218,27 +3193,53 @@ func subscriptionHasCurrentCSV(currentCSV string) subscriptionStateChecker {
32183193
}
32193194

32203195
func subscriptionHasCondition(condType operatorsv1alpha1.SubscriptionConditionType, status corev1.ConditionStatus, reason, message string) subscriptionStateChecker {
3196+
var lastCond operatorsv1alpha1.SubscriptionCondition
3197+
lastTime := time.Now()
3198+
// if status/reason/message meet expectations, then subscription state is considered met/true
3199+
// IFF this is the result of a recent change of status/reason/message
3200+
// else, cache the current status/reason/message for next loop/comparison
32213201
return func(subscription *operatorsv1alpha1.Subscription) bool {
32223202
cond := subscription.Status.GetCondition(condType)
32233203
if cond.Status == status && cond.Reason == reason && cond.Message == message {
3224-
fmt.Printf("subscription condition met %v\n", cond)
3204+
if lastCond.Status != cond.Status && lastCond.Reason != cond.Reason && lastCond.Message == cond.Message {
3205+
GinkgoT().Logf("waited %s subscription condition met %v\n", time.Since(lastTime), cond)
3206+
lastTime = time.Now()
3207+
lastCond = cond
3208+
}
32253209
return true
32263210
}
32273211

3228-
fmt.Printf("subscription condition not met: %v\n", cond)
3212+
if lastCond.Status != cond.Status && lastCond.Reason != cond.Reason && lastCond.Message == cond.Message {
3213+
GinkgoT().Logf("waited %s subscription condition not met: %v\n", time.Since(lastTime), cond)
3214+
lastTime = time.Now()
3215+
lastCond = cond
3216+
}
32293217
return false
32303218
}
32313219
}
32323220

32333221
func subscriptionDoesNotHaveCondition(condType operatorsv1alpha1.SubscriptionConditionType) subscriptionStateChecker {
3222+
var lastStatus corev1.ConditionStatus
3223+
lastTime := time.Now()
3224+
// if status meets expectations, then subscription state is considered met/true
3225+
// IFF this is the result of a recent change of status
3226+
// else, cache the current status for next loop/comparison
32343227
return func(subscription *operatorsv1alpha1.Subscription) bool {
32353228
cond := subscription.Status.GetCondition(condType)
32363229
if cond.Status == corev1.ConditionUnknown {
3237-
fmt.Printf("subscription condition not found\n")
3230+
if cond.Status != lastStatus {
3231+
GinkgoT().Logf("waited %s subscription condition not found\n", time.Since(lastTime))
3232+
lastStatus = cond.Status
3233+
lastTime = time.Now()
3234+
}
32383235
return true
32393236
}
32403237

3241-
fmt.Printf("subscription condition found: %v\n", cond)
3238+
if cond.Status != lastStatus {
3239+
GinkgoT().Logf("waited %s subscription condition found: %v\n", time.Since(lastTime), cond)
3240+
lastStatus = cond.Status
3241+
lastTime = time.Now()
3242+
}
32423243
return false
32433244
}
32443245
}
@@ -3365,6 +3366,35 @@ func createSubscriptionForCatalogWithSpec(t GinkgoTInterface, crc versioned.Inte
33653366
return buildSubscriptionCleanupFunc(crc, subscription)
33663367
}
33673368

3369+
func waitForSubscriptionToDelete(namespace, name string, c versioned.Interface) error {
3370+
var lastState operatorsv1alpha1.SubscriptionState
3371+
var lastReason operatorsv1alpha1.ConditionReason
3372+
lastTime := time.Now()
3373+
3374+
ctx.Ctx().Logf("waiting for subscription %s/%s to delete", namespace, name)
3375+
err := wait.Poll(pollInterval, pollDuration, func() (bool, error) {
3376+
sub, err := c.OperatorsV1alpha1().Subscriptions(namespace).Get(context.TODO(), name, metav1.GetOptions{})
3377+
if apierrors.IsNotFound(err) {
3378+
ctx.Ctx().Logf("subscription %s/%s deleted", namespace, name)
3379+
return true, nil
3380+
}
3381+
if err != nil {
3382+
ctx.Ctx().Logf("error getting subscription %s/%s: %v", namespace, name, err)
3383+
}
3384+
if sub != nil {
3385+
state, reason := sub.Status.State, sub.Status.Reason
3386+
if state != lastState || reason != lastReason {
3387+
ctx.Ctx().Logf("waited %s for subscription %s/%s status: %s (%s)", time.Since(lastTime), namespace, name, state, reason)
3388+
lastState, lastReason = state, reason
3389+
lastTime = time.Now()
3390+
}
3391+
}
3392+
return false, nil
3393+
})
3394+
3395+
return err
3396+
}
3397+
33683398
func checkDeploymentHasPodConfigNodeSelector(t GinkgoTInterface, client operatorclient.ClientInterface, csv *operatorsv1alpha1.ClusterServiceVersion, nodeSelector map[string]string) error {
33693399
resolver := install.StrategyResolver{}
33703400

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

+2
Original file line numberDiff line numberDiff line change
@@ -677,8 +677,10 @@ func createInternalCatalogSource(
677677
ctx.Ctx().Logf("Catalog source %s created", name)
678678

679679
cleanupInternalCatalogSource := func() {
680+
ctx.Ctx().Logf("Cleaning catalog source %s", name)
680681
configMapCleanup()
681682
buildCatalogSourceCleanupFunc(c, crc, namespace, catalogSource)()
683+
ctx.Ctx().Logf("Done cleaning catalog source %s", name)
682684
}
683685
return catalogSource, cleanupInternalCatalogSource
684686
}

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

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)