Skip to content

Commit b47f9e1

Browse files
Mikalai Radchukperdasilva
Mikalai Radchuk
authored andcommitted
Moves bundle unpack timeout into OperatorGroup
`operatorframework.io/bundle-unpack-timeout` is an internal annotation used for E2E testing. We need to move this out of InstallPlan in preparation to changes in the unpacking process: OLM will soon be creating unpack jobs before creating InstallPlan so we need to find a new place where we can set this annotation. Signed-off-by: Mikalai Radchuk <[email protected]>
1 parent b5a885e commit b47f9e1

File tree

6 files changed

+194
-43
lines changed

6 files changed

+194
-43
lines changed

pkg/controller/bundle/bundle_unpacker.go

+29
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
"github.com/operator-framework/api/pkg/operators/reference"
2828
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
29+
v1listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1"
2930
listersoperatorsv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
3031
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
3132
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/projection"
@@ -768,3 +769,31 @@ func getCondition(job *batchv1.Job, conditionType batchv1.JobConditionType) (con
768769
}
769770
return
770771
}
772+
773+
// OperatorGroupBundleUnpackTimeout returns bundle timeout from annotation if specified.
774+
// This is to overrides the --bundle-unpack-timeout flag value on per-OperatorGroup basis.
775+
// If the timeout cannot be parsed it's set to < 0 and subsequently ignored.
776+
func OperatorGroupBundleUnpackTimeout(logger *logrus.Logger, ogLister v1listers.OperatorGroupNamespaceLister) (time.Duration, error) {
777+
ignoreTimeout := -1 * time.Minute
778+
779+
ogs, err := ogLister.List(k8slabels.Everything())
780+
if err != nil || len(ogs) == 0 {
781+
return ignoreTimeout, nil
782+
}
783+
if len(ogs) != 1 {
784+
return ignoreTimeout, fmt.Errorf("found %d operatorGroups, expected 1", len(ogs))
785+
}
786+
787+
timeoutStr, ok := ogs[0].GetAnnotations()[BundleUnpackTimeoutAnnotationKey]
788+
if !ok {
789+
return ignoreTimeout, nil
790+
}
791+
792+
d, err := time.ParseDuration(timeoutStr)
793+
if err != nil {
794+
logger.Errorf("failed to parse unpack timeout annotation(%s: %s): %v", BundleUnpackTimeoutAnnotationKey, timeoutStr, err)
795+
return ignoreTimeout, nil
796+
}
797+
798+
return d, nil
799+
}

pkg/controller/bundle/bundle_unpacker_test.go

+122
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"testing"
77
"time"
88

9+
logrustest "github.com/sirupsen/logrus/hooks/test"
10+
"github.com/stretchr/testify/assert"
911
"github.com/stretchr/testify/require"
1012
batchv1 "k8s.io/api/batch/v1"
1113
corev1 "k8s.io/api/core/v1"
@@ -15,11 +17,14 @@ import (
1517
"k8s.io/apimachinery/pkg/runtime"
1618
"k8s.io/client-go/informers"
1719
k8sfake "k8s.io/client-go/kubernetes/fake"
20+
"k8s.io/client-go/tools/cache"
1821
"k8s.io/utils/pointer"
1922

23+
operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
2024
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
2125
crfake "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/fake"
2226
crinformers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions"
27+
v1listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1"
2328
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
2429
"github.com/operator-framework/operator-registry/pkg/api"
2530
"github.com/operator-framework/operator-registry/pkg/configmap"
@@ -1554,3 +1559,120 @@ func TestConfigMapUnpacker(t *testing.T) {
15541559
})
15551560
}
15561561
}
1562+
1563+
func TestOperatorGroupBundleUnpackTimeout(t *testing.T) {
1564+
nsName := "fake-ns"
1565+
testLogger, hook := logrustest.NewNullLogger()
1566+
1567+
for _, tc := range []struct {
1568+
name string
1569+
operatorGroups []*operatorsv1.OperatorGroup
1570+
expectedTimeout time.Duration
1571+
expectedError error
1572+
expectedLogMsg string
1573+
}{
1574+
{
1575+
name: "No operator groups exist",
1576+
expectedTimeout: -1 * time.Minute,
1577+
},
1578+
{
1579+
name: "Multiple operator groups exist",
1580+
operatorGroups: []*operatorsv1.OperatorGroup{
1581+
{
1582+
TypeMeta: metav1.TypeMeta{
1583+
Kind: operatorsv1.OperatorGroupKind,
1584+
APIVersion: operatorsv1.GroupVersion.String(),
1585+
},
1586+
ObjectMeta: metav1.ObjectMeta{
1587+
Name: "og1",
1588+
Namespace: nsName,
1589+
},
1590+
},
1591+
{
1592+
TypeMeta: metav1.TypeMeta{
1593+
Kind: operatorsv1.OperatorGroupKind,
1594+
APIVersion: operatorsv1.GroupVersion.String(),
1595+
},
1596+
ObjectMeta: metav1.ObjectMeta{
1597+
Name: "og2",
1598+
Namespace: nsName,
1599+
},
1600+
},
1601+
},
1602+
expectedTimeout: -1 * time.Minute,
1603+
expectedError: fmt.Errorf("found %d operatorGroups, expected 1", 2),
1604+
},
1605+
{
1606+
name: "One operator group exists with valid timeout annotation",
1607+
operatorGroups: []*operatorsv1.OperatorGroup{
1608+
{
1609+
TypeMeta: metav1.TypeMeta{
1610+
Kind: operatorsv1.OperatorGroupKind,
1611+
APIVersion: operatorsv1.GroupVersion.String(),
1612+
},
1613+
ObjectMeta: metav1.ObjectMeta{
1614+
Name: "og",
1615+
Namespace: nsName,
1616+
Annotations: map[string]string{BundleUnpackTimeoutAnnotationKey: "1m"},
1617+
},
1618+
},
1619+
},
1620+
expectedTimeout: 1 * time.Minute,
1621+
expectedError: nil,
1622+
},
1623+
{
1624+
name: "One operator group exists with no timeout annotation",
1625+
operatorGroups: []*operatorsv1.OperatorGroup{
1626+
{
1627+
TypeMeta: metav1.TypeMeta{
1628+
Kind: operatorsv1.OperatorGroupKind,
1629+
APIVersion: operatorsv1.GroupVersion.String(),
1630+
},
1631+
ObjectMeta: metav1.ObjectMeta{
1632+
Name: "og",
1633+
Namespace: nsName,
1634+
},
1635+
},
1636+
},
1637+
expectedTimeout: -1 * time.Minute,
1638+
},
1639+
{
1640+
name: "One operator group exists with invalid timeout annotation",
1641+
operatorGroups: []*operatorsv1.OperatorGroup{
1642+
{
1643+
TypeMeta: metav1.TypeMeta{
1644+
Kind: operatorsv1.OperatorGroupKind,
1645+
APIVersion: operatorsv1.GroupVersion.String(),
1646+
},
1647+
ObjectMeta: metav1.ObjectMeta{
1648+
Name: "og",
1649+
Namespace: nsName,
1650+
Annotations: map[string]string{BundleUnpackTimeoutAnnotationKey: "invalid"},
1651+
},
1652+
},
1653+
},
1654+
expectedTimeout: -1 * time.Minute,
1655+
expectedError: nil,
1656+
expectedLogMsg: "failed to parse unpack timeout annotation(operatorframework.io/bundle-unpack-timeout: invalid): time: invalid duration \"invalid\"",
1657+
},
1658+
} {
1659+
t.Run(tc.name, func(t *testing.T) {
1660+
ogIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
1661+
ogLister := v1listers.NewOperatorGroupLister(ogIndexer).OperatorGroups(nsName)
1662+
1663+
for _, og := range tc.operatorGroups {
1664+
err := ogIndexer.Add(og)
1665+
assert.NoError(t, err)
1666+
}
1667+
1668+
timeout, err := OperatorGroupBundleUnpackTimeout(testLogger, ogLister)
1669+
1670+
assert.Equal(t, tc.expectedTimeout, timeout)
1671+
assert.Equal(t, tc.expectedError, err)
1672+
1673+
if tc.expectedLogMsg != "" {
1674+
assert.Equal(t, tc.expectedLogMsg, hook.LastEntry().Message)
1675+
}
1676+
})
1677+
}
1678+
}

pkg/controller/operators/catalog/operator.go

+8-15
Original file line numberDiff line numberDiff line change
@@ -1408,23 +1408,10 @@ type UnpackedBundleReference struct {
14081408
Properties string `json:"properties"`
14091409
}
14101410

1411-
func (o *Operator) unpackBundles(plan *v1alpha1.InstallPlan) (bool, *v1alpha1.InstallPlan, error) {
1411+
func (o *Operator) unpackBundles(plan *v1alpha1.InstallPlan, unpackTimeout time.Duration) (bool, *v1alpha1.InstallPlan, error) {
14121412
out := plan.DeepCopy()
14131413
unpacked := true
14141414

1415-
// The bundle timeout annotation if specified overrides the --bundle-unpack-timeout flag value
1416-
// If the timeout cannot be parsed it's set to < 0 and subsequently ignored
1417-
unpackTimeout := -1 * time.Minute
1418-
timeoutStr, ok := plan.GetAnnotations()[bundle.BundleUnpackTimeoutAnnotationKey]
1419-
if ok {
1420-
d, err := time.ParseDuration(timeoutStr)
1421-
if err != nil {
1422-
o.logger.Errorf("failed to parse unpack timeout annotation(%s: %s): %v", bundle.BundleUnpackTimeoutAnnotationKey, timeoutStr, err)
1423-
} else {
1424-
unpackTimeout = d
1425-
}
1426-
}
1427-
14281415
var errs []error
14291416
for i := 0; i < len(out.Status.BundleLookups); i++ {
14301417
lookup := out.Status.BundleLookups[i]
@@ -1597,6 +1584,12 @@ func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) {
15971584
return
15981585
}
15991586

1587+
ogLister := o.lister.OperatorsV1().OperatorGroupLister().OperatorGroups(plan.GetNamespace())
1588+
unpackTimeout, err := bundle.OperatorGroupBundleUnpackTimeout(o.logger, ogLister)
1589+
if err != nil {
1590+
return err
1591+
}
1592+
16001593
querier := o.serviceAccountQuerier.NamespaceQuerier(plan.GetNamespace())
16011594
ref, err := querier()
16021595

@@ -1648,7 +1641,7 @@ func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) {
16481641
// Attempt to unpack bundles before installing
16491642
// Note: This should probably use the attenuated client to prevent users from resolving resources they otherwise don't have access to.
16501643
if len(plan.Status.BundleLookups) > 0 {
1651-
unpacked, out, err := o.unpackBundles(plan)
1644+
unpacked, out, err := o.unpackBundles(plan, unpackTimeout)
16521645
if err != nil {
16531646
// If the error was fatal capture and fail
16541647
if fatal := olmerrors.IsFatal(err); fatal {

test/e2e/fail_forward_e2e_test.go

+20-12
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
. "github.com/onsi/gomega"
1010
corev1 "k8s.io/api/core/v1"
1111
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/types"
1213
"sigs.k8s.io/controller-runtime/pkg/client"
1314

1415
operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
@@ -27,6 +28,7 @@ var _ = Describe("Fail Forward Upgrades", func() {
2728
ns corev1.Namespace
2829
crclient versioned.Interface
2930
c client.Client
31+
ogName string
3032
)
3133

3234
BeforeEach(func() {
@@ -45,6 +47,7 @@ var _ = Describe("Fail Forward Upgrades", func() {
4547
},
4648
}
4749
ns = SetupGeneratedTestNamespaceWithOperatorGroup(namespaceName, og)
50+
ogName = og.GetName()
4851
})
4952

5053
AfterEach(func() {
@@ -61,9 +64,9 @@ var _ = Describe("Fail Forward Upgrades", func() {
6164
)
6265

6366
BeforeEach(func() {
67+
By("deploying the testing catalog")
6468
provider, err := NewFileBasedFiledBasedCatalogProvider(filepath.Join(testdataDir, failForwardTestDataBaseDir, "example-operator.v0.1.0.yaml"))
6569
Expect(err).To(BeNil())
66-
6770
catalogSourceName = genName("mc-ip-failed-")
6871
magicCatalog = NewMagicCatalog(c, ns.GetName(), catalogSourceName, provider)
6972
Expect(magicCatalog.DeployCatalog(context.Background())).To(BeNil())
@@ -93,6 +96,9 @@ var _ = Describe("Fail Forward Upgrades", func() {
9396
_, err = fetchCSV(crclient, subscription.Status.CurrentCSV, ns.GetName(), buildCSVConditionChecker(operatorsv1alpha1.CSVPhaseSucceeded))
9497
Expect(err).ShouldNot(HaveOccurred())
9598

99+
By("patching the OperatorGroup to reduce the bundle unpacking timeout")
100+
addBundleUnpackTimeoutOGAnnotation(context.Background(), c, types.NamespacedName{Name: ogName, Namespace: ns.GetName()}, "1s")
101+
96102
By("updating the catalog with a broken v0.2.0 bundle image")
97103
brokenProvider, err := NewFileBasedFiledBasedCatalogProvider(filepath.Join(testdataDir, failForwardTestDataBaseDir, "example-operator.v0.2.0.yaml"))
98104
Expect(err).To(BeNil())
@@ -104,9 +110,6 @@ var _ = Describe("Fail Forward Upgrades", func() {
104110
subscription, err = fetchSubscription(crclient, subscription.GetNamespace(), subscription.GetName(), subscriptionHasInstallPlanDifferentChecker(originalInstallPlanRef.Name))
105111
Expect(err).Should(BeNil())
106112

107-
By("patching the installplan to reduce the bundle unpacking timeout")
108-
addBundleUnpackTimeoutIPAnnotation(context.Background(), c, objectRefToNamespacedName(subscription.Status.InstallPlanRef), "1s")
109-
110113
By("waiting for the bad InstallPlan to report a failed installation state")
111114
ref := subscription.Status.InstallPlanRef
112115
_, err = fetchInstallPlan(GinkgoT(), crclient, ref.Name, ref.Namespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseFailed))
@@ -129,18 +132,17 @@ var _ = Describe("Fail Forward Upgrades", func() {
129132
subscription, err = fetchSubscription(crclient, subscription.GetNamespace(), subscription.GetName(), subscriptionHasCurrentCSV("example-operator.v0.2.1"))
130133
Expect(err).Should(BeNil())
131134

132-
By("patching the installplan to reduce the bundle unpacking timeout")
133-
addBundleUnpackTimeoutIPAnnotation(context.Background(), c, objectRefToNamespacedName(subscription.Status.InstallPlanRef), "1s")
134-
135135
By("waiting for the bad v0.2.1 InstallPlan to report a failed installation state")
136136
ref := subscription.Status.InstallPlanRef
137137
_, err = fetchInstallPlan(GinkgoT(), crclient, ref.Name, ref.Namespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseFailed))
138138
Expect(err).To(BeNil())
139139

140+
By("patching the OperatorGroup to increase the bundle unpacking timeout")
141+
addBundleUnpackTimeoutOGAnnotation(context.Background(), c, types.NamespacedName{Name: ogName, Namespace: ns.GetName()}, "5m")
142+
140143
By("patching the catalog with a fixed version")
141144
fixedProvider, err := NewFileBasedFiledBasedCatalogProvider(filepath.Join(testdataDir, "fail-forward/multiple-bad-versions", "example-operator.v0.3.0.yaml"))
142145
Expect(err).To(BeNil())
143-
144146
err = magicCatalog.UpdateCatalog(context.Background(), fixedProvider)
145147
Expect(err).To(BeNil())
146148

@@ -150,10 +152,12 @@ var _ = Describe("Fail Forward Upgrades", func() {
150152
})
151153

152154
It("eventually reports a successful state when using skip ranges", func() {
155+
By("patching the OperatorGroup to increase the bundle unpacking timeout")
156+
addBundleUnpackTimeoutOGAnnotation(context.Background(), c, types.NamespacedName{Name: ogName, Namespace: ns.GetName()}, "5m")
157+
153158
By("patching the catalog with a fixed version")
154159
fixedProvider, err := NewFileBasedFiledBasedCatalogProvider(filepath.Join(testdataDir, "fail-forward/skip-range", "example-operator.v0.3.0.yaml"))
155160
Expect(err).To(BeNil())
156-
157161
err = magicCatalog.UpdateCatalog(context.Background(), fixedProvider)
158162
Expect(err).To(BeNil())
159163

@@ -162,10 +166,12 @@ var _ = Describe("Fail Forward Upgrades", func() {
162166
Expect(err).Should(BeNil())
163167
})
164168
It("eventually reports a successful state when using skips", func() {
169+
By("patching the OperatorGroup to increase the bundle unpacking timeout")
170+
addBundleUnpackTimeoutOGAnnotation(context.Background(), c, types.NamespacedName{Name: ogName, Namespace: ns.GetName()}, "5m")
171+
165172
By("patching the catalog with a fixed version")
166173
fixedProvider, err := NewFileBasedFiledBasedCatalogProvider(filepath.Join(testdataDir, "fail-forward/skips", "example-operator.v0.3.0.yaml"))
167174
Expect(err).To(BeNil())
168-
169175
err = magicCatalog.UpdateCatalog(context.Background(), fixedProvider)
170176
Expect(err).To(BeNil())
171177

@@ -174,10 +180,12 @@ var _ = Describe("Fail Forward Upgrades", func() {
174180
Expect(err).Should(BeNil())
175181
})
176182
It("eventually reports a failed state when using replaces", func() {
183+
By("patching the OperatorGroup to increase the bundle unpacking timeout")
184+
addBundleUnpackTimeoutOGAnnotation(context.Background(), c, types.NamespacedName{Name: ogName, Namespace: ns.GetName()}, "5m")
185+
177186
By("patching the catalog with a fixed version")
178187
fixedProvider, err := NewFileBasedFiledBasedCatalogProvider(filepath.Join(testdataDir, "fail-forward/replaces", "example-operator.v0.3.0.yaml"))
179188
Expect(err).To(BeNil())
180-
181189
err = magicCatalog.UpdateCatalog(context.Background(), fixedProvider)
182190
Expect(err).To(BeNil())
183191

@@ -200,9 +208,9 @@ var _ = Describe("Fail Forward Upgrades", func() {
200208
)
201209

202210
BeforeEach(func() {
211+
By("deploying the testing catalog")
203212
provider, err := NewFileBasedFiledBasedCatalogProvider(filepath.Join(testdataDir, failForwardTestDataBaseDir, "example-operator.v0.1.0.yaml"))
204213
Expect(err).To(BeNil())
205-
206214
catalogSourceName = genName("mc-csv-failed-")
207215
magicCatalog = NewMagicCatalog(c, ns.GetName(), catalogSourceName, provider)
208216
Expect(magicCatalog.DeployCatalog(context.Background())).To(BeNil())

0 commit comments

Comments
 (0)