From d75ca3b7ae8da155d39475b20c9b5edea6d27a2d Mon Sep 17 00:00:00 2001 From: Daniel Sover Date: Thu, 9 Jan 2020 16:24:50 -0500 Subject: [PATCH] fix: refactor catalog polling spec to use more general update strategy field --- .../0000_50_olm_06-catalogsource.crd.yaml | 26 +++++--- doc/design/catalog-polling.md | 14 ++++- .../0000_50_olm_06-catalogsource.crd.yaml | 26 +++++--- pkg/api/apis/operators/catalogsource_types.go | 20 ++++-- .../operators/v1alpha1/catalogsource_types.go | 45 ++++++++------ pkg/api/apis/operators/v1alpha1/types_test.go | 35 ++++++++--- .../v1alpha1/zz_generated.conversion.go | 62 ++++++++++++++----- .../v1alpha1/zz_generated.deepcopy.go | 43 ++++++++++--- .../apis/operators/zz_generated.deepcopy.go | 43 ++++++++++--- pkg/controller/operators/catalog/operator.go | 2 +- pkg/controller/registry/reconciler/grpc.go | 4 +- .../registry/reconciler/reconciler.go | 2 +- test/e2e/catalog_e2e_test.go | 7 ++- 13 files changed, 231 insertions(+), 98 deletions(-) diff --git a/deploy/chart/templates/0000_50_olm_06-catalogsource.crd.yaml b/deploy/chart/templates/0000_50_olm_06-catalogsource.crd.yaml index 9125273e71..fd14d98372 100644 --- a/deploy/chart/templates/0000_50_olm_06-catalogsource.crd.yaml +++ b/deploy/chart/templates/0000_50_olm_06-catalogsource.crd.yaml @@ -97,16 +97,6 @@ spec: a registry-server with. Only used when SourceType = SourceTypeGrpc. If present, the address field is ignored. type: string - poll: - description: Poll is used to determine the time interval between checks - of the latest catalog source version. The catalog operator polls to - see if a new version of the catalog source is available. If available, - the latest image is pulled and gRPC traffic is directed to the latest - catalog source. - type: object - properties: - interval: - type: string publisher: type: string secrets: @@ -119,6 +109,22 @@ spec: sourceType: description: SourceType is the type of source type: string + updateStrategy: + description: UpdateStrategy defines how updated catalog source images + can be discovered Consists of an interval that defines polling duration + and an embedded strategy type + type: object + properties: + registryPoll: + type: object + properties: + interval: + description: Interval is used to determine the time interval + between checks of the latest catalog source version. The catalog + operator polls to see if a new version of the catalog source + is available. If available, the latest image is pulled and + gRPC traffic is directed to the latest catalog source. + type: string status: type: object properties: diff --git a/doc/design/catalog-polling.md b/doc/design/catalog-polling.md index 8bce722ac1..b45c8914c2 100644 --- a/doc/design/catalog-polling.md +++ b/doc/design/catalog-polling.md @@ -11,6 +11,10 @@ This is the latest version of the X operator in the catalog source. Lets say Ope to include the v2.0 version of the X operator and pushed to the same `master` tag. With catalog polling enabled, OLM will pull down the newer version of the catalog source image and route service traffic to the newer pod. The existing subscription will seamlessly create the v2.0 operator and remove the old v1.0 one. +Each type of check for an updated catalog source is called an `updateStrategy`. Only one `updateStrategy` is supported at a time. +`registryPoll` is a type of `updateStrategy` that checks an image registry for an updated version of the same tag. The `interval` defines +the amount of time between each successive poll. + ## Example Spec Here is an example catalog source that polls `quay.io/my-catalogs/my-catalog:master` every 45 minutes to see if the image has been updated. @@ -23,8 +27,9 @@ spec: displayName: CatalogSource Test sourceType: grpc image: quay.io/my-catalogs/my-catalog:master - poll: - interval: 45m + updateStrategy: + registryPoll: + interval: 2m ``` It is required for the catalog source to be sourceType grpc and be backed by an image for polling to work. @@ -33,4 +38,7 @@ It is required for the catalog source to be sourceType grpc and be backed by an * The polling sequence is not instantaneous - it can take up to 15 minutes from each poll for the new catalog source pod to be deployed into the cluster. It may take longer for larger clusters. * Because OLM pulls down the image every poll interval and starts the pod, to see if its updated, the updated catalog pod must be able to be -scheduled onto the cluster. If the cluster is at absolutely maximum capacity, without autoscaling enabled, this feature may not work. \ No newline at end of file +scheduled onto the cluster. If the cluster is at absolutely maximum capacity, without autoscaling enabled, this feature may not work. +* OLM checks to see whether the container ImageID has changed between the old and new catalog source image when determining if an upgrade +is in order. It does not actually parse the image content itself to check for later CSVs. If there is a bad upgrade to the catalog source image, +simply overwrite the tag with another version and it will be pulled down, or delete and recreate the catalog source. \ No newline at end of file diff --git a/manifests/0000_50_olm_06-catalogsource.crd.yaml b/manifests/0000_50_olm_06-catalogsource.crd.yaml index 9125273e71..fd14d98372 100644 --- a/manifests/0000_50_olm_06-catalogsource.crd.yaml +++ b/manifests/0000_50_olm_06-catalogsource.crd.yaml @@ -97,16 +97,6 @@ spec: a registry-server with. Only used when SourceType = SourceTypeGrpc. If present, the address field is ignored. type: string - poll: - description: Poll is used to determine the time interval between checks - of the latest catalog source version. The catalog operator polls to - see if a new version of the catalog source is available. If available, - the latest image is pulled and gRPC traffic is directed to the latest - catalog source. - type: object - properties: - interval: - type: string publisher: type: string secrets: @@ -119,6 +109,22 @@ spec: sourceType: description: SourceType is the type of source type: string + updateStrategy: + description: UpdateStrategy defines how updated catalog source images + can be discovered Consists of an interval that defines polling duration + and an embedded strategy type + type: object + properties: + registryPoll: + type: object + properties: + interval: + description: Interval is used to determine the time interval + between checks of the latest catalog source version. The catalog + operator polls to see if a new version of the catalog source + is available. If available, the latest image is pulled and + gRPC traffic is directed to the latest catalog source. + type: string status: type: object properties: diff --git a/pkg/api/apis/operators/catalogsource_types.go b/pkg/api/apis/operators/catalogsource_types.go index 526a946b51..ff810f550a 100644 --- a/pkg/api/apis/operators/catalogsource_types.go +++ b/pkg/api/apis/operators/catalogsource_types.go @@ -47,11 +47,10 @@ type CatalogSourceSpec struct { // +Optional Image string - // Poll is used to determine the time interval between checks of the latest catalog source version. - // The catalog operator polls to see if a new version of the catalog source is available. - // If available, the latest image is pulled and gRPC traffic is directed to the latest catalog source. + // UpdateStrategy defines how updated catalog source images can be discovered + // Consists of an interval that defines polling duration and an embedded strategy type // +Optional - Poll *Poll + UpdateStrategy *UpdateStrategy // Secrets represent set of secrets that can be used to access the contents of the catalog. // It is best to keep this list small, since each will need to be tried for every catalog entry. @@ -65,8 +64,17 @@ type CatalogSourceSpec struct { Icon Icon } -type Poll struct { - Interval metav1.Duration +// UpdateStrategy holds all the different types of catalog source update strategies +// Currently only registry polling strategy is implemented +type UpdateStrategy struct { + *RegistryPoll +} + +type RegistryPoll struct { + // Interval is used to determine the time interval between checks of the latest catalog source version. + // The catalog operator polls to see if a new version of the catalog source is available. + // If available, the latest image is pulled and gRPC traffic is directed to the latest catalog source. + Interval *metav1.Duration } type RegistryServiceStatus struct { diff --git a/pkg/api/apis/operators/v1alpha1/catalogsource_types.go b/pkg/api/apis/operators/v1alpha1/catalogsource_types.go index 793e2e9aff..00f45c11a1 100644 --- a/pkg/api/apis/operators/v1alpha1/catalogsource_types.go +++ b/pkg/api/apis/operators/v1alpha1/catalogsource_types.go @@ -55,11 +55,10 @@ type CatalogSourceSpec struct { // +Optional Image string `json:"image,omitempty"` - // Poll is used to determine the time interval between checks of the latest catalog source version. - // The catalog operator polls to see if a new version of the catalog source is available. - // If available, the latest image is pulled and gRPC traffic is directed to the latest catalog source. + // UpdateStrategy defines how updated catalog source images can be discovered + // Consists of an interval that defines polling duration and an embedded strategy type // +Optional - Poll *Poll `json:"poll,omitempty"` + UpdateStrategy *UpdateStrategy `json:"updateStrategy,omitempty"` // Secrets represent set of secrets that can be used to access the contents of the catalog. // It is best to keep this list small, since each will need to be tried for every catalog entry. @@ -73,8 +72,17 @@ type CatalogSourceSpec struct { Icon Icon `json:"icon,omitempty"` } -type Poll struct { - Interval metav1.Duration `json:"interval,omitempty"` +// UpdateStrategy holds all the different types of catalog source update strategies +// Currently only registry polling strategy is implemented +type UpdateStrategy struct { + *RegistryPoll `json:"registryPoll,omitempty"` +} + +type RegistryPoll struct { + // Interval is used to determine the time interval between checks of the latest catalog source version. + // The catalog operator polls to see if a new version of the catalog source is available. + // If available, the latest image is pulled and gRPC traffic is directed to the latest catalog source. + Interval *metav1.Duration `json:"interval,omitempty"` } type RegistryServiceStatus struct { @@ -157,28 +165,26 @@ func (c *CatalogSource) SetLastUpdateTime() { } // Check if it is time to update based on polling setting -func (c *CatalogSource) ReadyToUpdate() bool { - if !c.PollingEnabled() { +func (c *CatalogSource) Update() bool { + if !c.Poll() { return false } - interval := c.Spec.Poll.Interval.Duration - logrus.WithField("CatalogSource", c.Name).Infof("polling interval %v", interval) + interval := c.Spec.UpdateStrategy.Interval.Duration latest := c.Status.LatestImageRegistryPoll if latest == nil { - logrus.WithField("CatalogSource", c.Name).Infof("latest poll %v", latest) + logrus.WithField("CatalogSource", c.Name).Debugf("latest poll %v", latest) } else { - logrus.WithField("CatalogSource", c.Name).Infof("latest poll %v", *c.Status.LatestImageRegistryPoll) + logrus.WithField("CatalogSource", c.Name).Debugf("latest poll %v", *c.Status.LatestImageRegistryPoll) } - logrus.WithField("CatalogSource", c.Name).Infof("polling interval is zero %t", c.Status.LatestImageRegistryPoll.IsZero()) if c.Status.LatestImageRegistryPoll.IsZero() { - logrus.WithField("CatalogSource", c.Name).Infof("creation interval plus interval before now %t", c.CreationTimestamp.Add(interval).Before(time.Now())) + logrus.WithField("CatalogSource", c.Name).Debugf("creation timestamp plus interval before now %t", c.CreationTimestamp.Add(interval).Before(time.Now())) if c.CreationTimestamp.Add(interval).Before(time.Now()) { return true } } else { - logrus.WithField("CatalogSource", c.Name).Infof("latest poll plus interval before now %t", c.Status.LatestImageRegistryPoll.Add(interval).Before(time.Now())) + logrus.WithField("CatalogSource", c.Name).Debugf("latest poll plus interval before now %t", c.Status.LatestImageRegistryPoll.Add(interval).Before(time.Now())) if c.Status.LatestImageRegistryPoll.Add(interval).Before(time.Now()) { return true } @@ -187,10 +193,13 @@ func (c *CatalogSource) ReadyToUpdate() bool { return false } -// CatalogPollingEnabled determines whether the polling feature is enabled on the particular catalog source -func (c *CatalogSource) PollingEnabled() bool { +// Poll determines whether the polling feature is enabled on the particular catalog source +func (c *CatalogSource) Poll() bool { + if c.Spec.UpdateStrategy == nil { + return false + } // if polling interval is zero polling will not be done - if c.Spec.Poll == nil { + if c.Spec.UpdateStrategy.RegistryPoll == nil { return false } // if catalog source is not backed by an image polling will not be done diff --git a/pkg/api/apis/operators/v1alpha1/types_test.go b/pkg/api/apis/operators/v1alpha1/types_test.go index 91fe687631..93df990926 100644 --- a/pkg/api/apis/operators/v1alpha1/types_test.go +++ b/pkg/api/apis/operators/v1alpha1/types_test.go @@ -105,7 +105,7 @@ func TestOwnsCRD(t *testing.T) { } } -func TestCatalogSource_ReadyToUpdate(t *testing.T) { +func TestCatalogSource_Update(t *testing.T) { var table = []struct { description string catsrc CatalogSource @@ -117,7 +117,11 @@ func TestCatalogSource_ReadyToUpdate(t *testing.T) { catsrc: CatalogSource{ ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.Time{Time: time.Now()}}, Spec: CatalogSourceSpec{ - Poll: &Poll{Interval: metav1.Duration{Duration: 1 * time.Second}}, + UpdateStrategy: &UpdateStrategy{ + RegistryPoll: &RegistryPoll{ + Interval: &metav1.Duration{Duration: 1 * time.Second}, + }, + }, Image: "mycatsrcimage", SourceType: SourceTypeGrpc}, }, @@ -129,7 +133,11 @@ func TestCatalogSource_ReadyToUpdate(t *testing.T) { catsrc: CatalogSource{ ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.Time{Time: time.Now()}}, Spec: CatalogSourceSpec{ - Poll: &Poll{Interval: metav1.Duration{Duration: 1 * time.Second}}, + UpdateStrategy: &UpdateStrategy{ + RegistryPoll: &RegistryPoll{ + Interval: &metav1.Duration{Duration: 1 * time.Second}, + }, + }, Image: "mycatsrcimage", SourceType: SourceTypeGrpc, }, @@ -143,7 +151,11 @@ func TestCatalogSource_ReadyToUpdate(t *testing.T) { catsrc: CatalogSource{ ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.Time{Time: time.Now()}}, Spec: CatalogSourceSpec{ - Poll: &Poll{Interval: metav1.Duration{Duration: 1 * time.Second}}, + UpdateStrategy: &UpdateStrategy{ + RegistryPoll: &RegistryPoll{ + Interval: &metav1.Duration{Duration: 1 * time.Second}, + }, + }, Image: "mycatsrcimage", SourceType: SourceTypeGrpc, }, @@ -156,11 +168,11 @@ func TestCatalogSource_ReadyToUpdate(t *testing.T) { for i, tt := range table { time.Sleep(table[i].sleep) - require.Equal(t, tt.result, table[i].catsrc.ReadyToUpdate(), table[i].description) + require.Equal(t, tt.result, table[i].catsrc.Update(), table[i].description) } } -func TestCatalogSource_PollingEnabled(t *testing.T) { +func TestCatalogSource_Poll(t *testing.T) { var table = []struct { description string catsrc CatalogSource @@ -182,14 +194,17 @@ func TestCatalogSource_PollingEnabled(t *testing.T) { catsrc: CatalogSource{Spec: CatalogSourceSpec{ Image: "my-image", SourceType: SourceTypeGrpc, - Poll: &Poll{Interval: metav1.Duration{ - Duration: 1 * time.Minute, - }}}, + UpdateStrategy: &UpdateStrategy{ + RegistryPoll: &RegistryPoll{ + Interval: &metav1.Duration{Duration: 1 * time.Second}, + }, + }, + }, }, result: true, }, } for i, tt := range table { - require.Equal(t, tt.result, table[i].catsrc.PollingEnabled(), table[i].description) + require.Equal(t, tt.result, table[i].catsrc.Poll(), table[i].description) } } diff --git a/pkg/api/apis/operators/v1alpha1/zz_generated.conversion.go b/pkg/api/apis/operators/v1alpha1/zz_generated.conversion.go index 2639624994..efd707efd8 100644 --- a/pkg/api/apis/operators/v1alpha1/zz_generated.conversion.go +++ b/pkg/api/apis/operators/v1alpha1/zz_generated.conversion.go @@ -350,13 +350,13 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*Poll)(nil), (*operators.Poll)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Poll_To_operators_Poll(a.(*Poll), b.(*operators.Poll), scope) + if err := s.AddGeneratedConversionFunc((*RegistryPoll)(nil), (*operators.RegistryPoll)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_RegistryPoll_To_operators_RegistryPoll(a.(*RegistryPoll), b.(*operators.RegistryPoll), scope) }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*operators.Poll)(nil), (*Poll)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_operators_Poll_To_v1alpha1_Poll(a.(*operators.Poll), b.(*Poll), scope) + if err := s.AddGeneratedConversionFunc((*operators.RegistryPoll)(nil), (*RegistryPoll)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_operators_RegistryPoll_To_v1alpha1_RegistryPoll(a.(*operators.RegistryPoll), b.(*RegistryPoll), scope) }); err != nil { return err } @@ -520,6 +520,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*UpdateStrategy)(nil), (*operators.UpdateStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_UpdateStrategy_To_operators_UpdateStrategy(a.(*UpdateStrategy), b.(*operators.UpdateStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*operators.UpdateStrategy)(nil), (*UpdateStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_operators_UpdateStrategy_To_v1alpha1_UpdateStrategy(a.(*operators.UpdateStrategy), b.(*UpdateStrategy), scope) + }); err != nil { + return err + } return nil } @@ -832,7 +842,7 @@ func autoConvert_v1alpha1_CatalogSourceSpec_To_operators_CatalogSourceSpec(in *C out.ConfigMap = in.ConfigMap out.Address = in.Address out.Image = in.Image - out.Poll = (*operators.Poll)(unsafe.Pointer(in.Poll)) + out.UpdateStrategy = (*operators.UpdateStrategy)(unsafe.Pointer(in.UpdateStrategy)) out.Secrets = *(*[]string)(unsafe.Pointer(&in.Secrets)) out.DisplayName = in.DisplayName out.Description = in.Description @@ -853,7 +863,7 @@ func autoConvert_operators_CatalogSourceSpec_To_v1alpha1_CatalogSourceSpec(in *o out.ConfigMap = in.ConfigMap out.Address = in.Address out.Image = in.Image - out.Poll = (*Poll)(unsafe.Pointer(in.Poll)) + out.UpdateStrategy = (*UpdateStrategy)(unsafe.Pointer(in.UpdateStrategy)) out.Secrets = *(*[]string)(unsafe.Pointer(&in.Secrets)) out.DisplayName = in.DisplayName out.Description = in.Description @@ -1453,24 +1463,24 @@ func Convert_operators_NamedInstallStrategy_To_v1alpha1_NamedInstallStrategy(in return autoConvert_operators_NamedInstallStrategy_To_v1alpha1_NamedInstallStrategy(in, out, s) } -func autoConvert_v1alpha1_Poll_To_operators_Poll(in *Poll, out *operators.Poll, s conversion.Scope) error { - out.Interval = in.Interval +func autoConvert_v1alpha1_RegistryPoll_To_operators_RegistryPoll(in *RegistryPoll, out *operators.RegistryPoll, s conversion.Scope) error { + out.Interval = (*metav1.Duration)(unsafe.Pointer(in.Interval)) return nil } -// Convert_v1alpha1_Poll_To_operators_Poll is an autogenerated conversion function. -func Convert_v1alpha1_Poll_To_operators_Poll(in *Poll, out *operators.Poll, s conversion.Scope) error { - return autoConvert_v1alpha1_Poll_To_operators_Poll(in, out, s) +// Convert_v1alpha1_RegistryPoll_To_operators_RegistryPoll is an autogenerated conversion function. +func Convert_v1alpha1_RegistryPoll_To_operators_RegistryPoll(in *RegistryPoll, out *operators.RegistryPoll, s conversion.Scope) error { + return autoConvert_v1alpha1_RegistryPoll_To_operators_RegistryPoll(in, out, s) } -func autoConvert_operators_Poll_To_v1alpha1_Poll(in *operators.Poll, out *Poll, s conversion.Scope) error { - out.Interval = in.Interval +func autoConvert_operators_RegistryPoll_To_v1alpha1_RegistryPoll(in *operators.RegistryPoll, out *RegistryPoll, s conversion.Scope) error { + out.Interval = (*metav1.Duration)(unsafe.Pointer(in.Interval)) return nil } -// Convert_operators_Poll_To_v1alpha1_Poll is an autogenerated conversion function. -func Convert_operators_Poll_To_v1alpha1_Poll(in *operators.Poll, out *Poll, s conversion.Scope) error { - return autoConvert_operators_Poll_To_v1alpha1_Poll(in, out, s) +// Convert_operators_RegistryPoll_To_v1alpha1_RegistryPoll is an autogenerated conversion function. +func Convert_operators_RegistryPoll_To_v1alpha1_RegistryPoll(in *operators.RegistryPoll, out *RegistryPoll, s conversion.Scope) error { + return autoConvert_operators_RegistryPoll_To_v1alpha1_RegistryPoll(in, out, s) } func autoConvert_v1alpha1_RegistryServiceStatus_To_operators_RegistryServiceStatus(in *RegistryServiceStatus, out *operators.RegistryServiceStatus, s conversion.Scope) error { @@ -1928,3 +1938,23 @@ func autoConvert_operators_SubscriptionStatus_To_v1alpha1_SubscriptionStatus(in func Convert_operators_SubscriptionStatus_To_v1alpha1_SubscriptionStatus(in *operators.SubscriptionStatus, out *SubscriptionStatus, s conversion.Scope) error { return autoConvert_operators_SubscriptionStatus_To_v1alpha1_SubscriptionStatus(in, out, s) } + +func autoConvert_v1alpha1_UpdateStrategy_To_operators_UpdateStrategy(in *UpdateStrategy, out *operators.UpdateStrategy, s conversion.Scope) error { + out.RegistryPoll = (*operators.RegistryPoll)(unsafe.Pointer(in.RegistryPoll)) + return nil +} + +// Convert_v1alpha1_UpdateStrategy_To_operators_UpdateStrategy is an autogenerated conversion function. +func Convert_v1alpha1_UpdateStrategy_To_operators_UpdateStrategy(in *UpdateStrategy, out *operators.UpdateStrategy, s conversion.Scope) error { + return autoConvert_v1alpha1_UpdateStrategy_To_operators_UpdateStrategy(in, out, s) +} + +func autoConvert_operators_UpdateStrategy_To_v1alpha1_UpdateStrategy(in *operators.UpdateStrategy, out *UpdateStrategy, s conversion.Scope) error { + out.RegistryPoll = (*RegistryPoll)(unsafe.Pointer(in.RegistryPoll)) + return nil +} + +// Convert_operators_UpdateStrategy_To_v1alpha1_UpdateStrategy is an autogenerated conversion function. +func Convert_operators_UpdateStrategy_To_v1alpha1_UpdateStrategy(in *operators.UpdateStrategy, out *UpdateStrategy, s conversion.Scope) error { + return autoConvert_operators_UpdateStrategy_To_v1alpha1_UpdateStrategy(in, out, s) +} diff --git a/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go b/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go index 493d34dea2..4f8d90a942 100644 --- a/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go @@ -321,10 +321,10 @@ func (in *CatalogSourceList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CatalogSourceSpec) DeepCopyInto(out *CatalogSourceSpec) { *out = *in - if in.Poll != nil { - in, out := &in.Poll, &out.Poll - *out = new(Poll) - **out = **in + if in.UpdateStrategy != nil { + in, out := &in.UpdateStrategy, &out.UpdateStrategy + *out = new(UpdateStrategy) + (*in).DeepCopyInto(*out) } if in.Secrets != nil { in, out := &in.Secrets, &out.Secrets @@ -922,18 +922,22 @@ func (in *NamedInstallStrategy) DeepCopy() *NamedInstallStrategy { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Poll) DeepCopyInto(out *Poll) { +func (in *RegistryPoll) DeepCopyInto(out *RegistryPoll) { *out = *in - out.Interval = in.Interval + if in.Interval != nil { + in, out := &in.Interval, &out.Interval + *out = new(metav1.Duration) + **out = **in + } return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Poll. -func (in *Poll) DeepCopy() *Poll { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryPoll. +func (in *RegistryPoll) DeepCopy() *RegistryPoll { if in == nil { return nil } - out := new(Poll) + out := new(RegistryPoll) in.DeepCopyInto(out) return out } @@ -1381,3 +1385,24 @@ func (in *SubscriptionStatus) DeepCopy() *SubscriptionStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpdateStrategy) DeepCopyInto(out *UpdateStrategy) { + *out = *in + if in.RegistryPoll != nil { + in, out := &in.RegistryPoll, &out.RegistryPoll + *out = new(RegistryPoll) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateStrategy. +func (in *UpdateStrategy) DeepCopy() *UpdateStrategy { + if in == nil { + return nil + } + out := new(UpdateStrategy) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/api/apis/operators/zz_generated.deepcopy.go b/pkg/api/apis/operators/zz_generated.deepcopy.go index 1d5d3f7089..f006514e7a 100644 --- a/pkg/api/apis/operators/zz_generated.deepcopy.go +++ b/pkg/api/apis/operators/zz_generated.deepcopy.go @@ -321,10 +321,10 @@ func (in *CatalogSourceList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CatalogSourceSpec) DeepCopyInto(out *CatalogSourceSpec) { *out = *in - if in.Poll != nil { - in, out := &in.Poll, &out.Poll - *out = new(Poll) - **out = **in + if in.UpdateStrategy != nil { + in, out := &in.UpdateStrategy, &out.UpdateStrategy + *out = new(UpdateStrategy) + (*in).DeepCopyInto(*out) } if in.Secrets != nil { in, out := &in.Secrets, &out.Secrets @@ -1039,18 +1039,22 @@ func (in *OperatorGroupStatus) DeepCopy() *OperatorGroupStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Poll) DeepCopyInto(out *Poll) { +func (in *RegistryPoll) DeepCopyInto(out *RegistryPoll) { *out = *in - out.Interval = in.Interval + if in.Interval != nil { + in, out := &in.Interval, &out.Interval + *out = new(metav1.Duration) + **out = **in + } return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Poll. -func (in *Poll) DeepCopy() *Poll { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryPoll. +func (in *RegistryPoll) DeepCopy() *RegistryPoll { if in == nil { return nil } - out := new(Poll) + out := new(RegistryPoll) in.DeepCopyInto(out) return out } @@ -1498,3 +1502,24 @@ func (in *SubscriptionStatus) DeepCopy() *SubscriptionStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpdateStrategy) DeepCopyInto(out *UpdateStrategy) { + *out = *in + if in.RegistryPoll != nil { + in, out := &in.RegistryPoll, &out.RegistryPoll + *out = new(RegistryPoll) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateStrategy. +func (in *UpdateStrategy) DeepCopy() *UpdateStrategy { + if in == nil { + return nil + } + out := new(UpdateStrategy) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/controller/operators/catalog/operator.go b/pkg/controller/operators/catalog/operator.go index 9bafe7d2d0..4012e350a5 100644 --- a/pkg/controller/operators/catalog/operator.go +++ b/pkg/controller/operators/catalog/operator.go @@ -552,7 +552,7 @@ func (o *Operator) syncRegistryServer(logger *logrus.Entry, in *v1alpha1.Catalog logger.Debug("registry state good") continueSync = true // Check if registryService is ready for polling update - if !out.ReadyToUpdate() { + if !out.Update() { return } } diff --git a/pkg/controller/registry/reconciler/grpc.go b/pkg/controller/registry/reconciler/grpc.go index 010bcd9ae8..78e77f3bca 100644 --- a/pkg/controller/registry/reconciler/grpc.go +++ b/pkg/controller/registry/reconciler/grpc.go @@ -181,7 +181,7 @@ func (c *GrpcRegistryReconciler) ensurePod(source grpcCatalogSourceDecorator, ov // ensureUpdatePod checks that for the same catalog source version the same imageID is running func (c *GrpcRegistryReconciler) ensureUpdatePod(source grpcCatalogSourceDecorator) error { - if !source.PollingEnabled() { + if !source.Poll() { return nil } var updateFlag bool @@ -218,7 +218,7 @@ func (c *GrpcRegistryReconciler) ensureUpdatePod(source grpcCatalogSourceDecorat logrus.WithField("CatalogSource", source.GetName()).Info("no image update for catalogsource pod") } - if source.ReadyToUpdate() { + if source.Update() { logrus.WithField("CatalogSource", source.GetName()).Info("creating new catalog source update pod") // Clean up outdated update pod(s) before creating a new update pod currentUpdatePods = c.currentUpdatePods(source) diff --git a/pkg/controller/registry/reconciler/reconciler.go b/pkg/controller/registry/reconciler/reconciler.go index 990367149b..32be5ef662 100644 --- a/pkg/controller/registry/reconciler/reconciler.go +++ b/pkg/controller/registry/reconciler/reconciler.go @@ -88,7 +88,7 @@ func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient func Pod(source *v1alpha1.CatalogSource, name string, image string, labels map[string]string, readinessDelay int32, livenessDelay int32) *v1.Pod { // ensure catalog image is pulled always if catalog polling is configured var pullPolicy v1.PullPolicy - if source.Spec.Poll != nil { + if source.Spec.UpdateStrategy != nil { pullPolicy = v1.PullAlways } else { pullPolicy = v1.PullIfNotPresent diff --git a/test/e2e/catalog_e2e_test.go b/test/e2e/catalog_e2e_test.go index cf7603ec34..3ddd0cdbe3 100644 --- a/test/e2e/catalog_e2e_test.go +++ b/test/e2e/catalog_e2e_test.go @@ -750,9 +750,10 @@ func TestCatalogImageUpdate(t *testing.T) { Spec: v1alpha1.CatalogSourceSpec{ SourceType: v1alpha1.SourceTypeGrpc, Image: oldImage[9:], // strip off docker:// - Poll: &v1alpha1.Poll{ - Interval: metav1.Duration{ - Duration: 1 * time.Minute}, + UpdateStrategy: &v1alpha1.UpdateStrategy{ + RegistryPoll: &v1alpha1.RegistryPoll{ + Interval: &metav1.Duration{Duration: 1 * time.Minute}, + }, }, }, }