diff --git a/staging/operator-lifecycle-manager/Makefile b/staging/operator-lifecycle-manager/Makefile index 007c1c6680..02d1bfb6b2 100644 --- a/staging/operator-lifecycle-manager/Makefile +++ b/staging/operator-lifecycle-manager/Makefile @@ -29,7 +29,11 @@ GO := GO111MODULE=on GOFLAGS="$(MOD_FLAGS)" go GINKGO := $(GO) run github.com/onsi/ginkgo/v2/ginkgo BINDATA := $(GO) run github.com/go-bindata/go-bindata/v3/go-bindata GIT_COMMIT := $(shell git rev-parse HEAD) - +ifeq ($(shell arch), arm64) +ARCH := arm64 +else +ARCH := 386 +endif # Phony prerequisite for targets that rely on the go build cache to determine staleness. .PHONY: build test clean vendor \ coverage coverage-html e2e \ @@ -82,15 +86,15 @@ build-coverage: build_cmd=test -c -covermode=count -coverpkg ./pkg/controller/.. build-coverage: clean $(CMDS) build-linux: build_cmd=build -build-linux: arch_flags=GOOS=linux GOARCH=386 +build-linux: arch_flags=GOOS=linux GOARCH=$(ARCH) build-linux: clean $(CMDS) build-wait: clean bin/wait bin/wait: FORCE - GOOS=linux GOARCH=386 go build $(MOD_FLAGS) -o $@ $(PKG)/test/e2e/wait + GOOS=linux GOARCH=$(ARCH) go build $(MOD_FLAGS) -o $@ $(PKG)/test/e2e/wait -build-util-linux: arch_flags=GOOS=linux GOARCH=386 +build-util-linux: arch_flags=GOOS=linux GOARCH=$(ARCH) build-util-linux: build-util build-util: bin/cpb diff --git a/staging/operator-lifecycle-manager/doc/install/install.md b/staging/operator-lifecycle-manager/doc/install/install.md index b842906146..4be3e31aba 100644 --- a/staging/operator-lifecycle-manager/doc/install/install.md +++ b/staging/operator-lifecycle-manager/doc/install/install.md @@ -25,7 +25,7 @@ This command starts minikube, builds the OLM containers locally with the minikub $ make run-local ``` -You can verify that the OLM components have been successfully deployed by running `kubectl -n local get deployments` +You can verify that the OLM components have been successfully deployed by running `kubectl -n olm get deployments` **NOTE** It is recommended for development purposes and will use the source locally diff --git a/staging/operator-lifecycle-manager/go.mod b/staging/operator-lifecycle-manager/go.mod index b1802e4368..fd86bb7a08 100644 --- a/staging/operator-lifecycle-manager/go.mod +++ b/staging/operator-lifecycle-manager/go.mod @@ -22,9 +22,9 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/onsi/ginkgo/v2 v2.1.3 github.com/onsi/gomega v1.18.1 - github.com/openshift/api v0.0.0-20220525145417-ee5b62754c68 - github.com/openshift/client-go v0.0.0-20220525160904-9e1acff93e4a - github.com/operator-framework/api v0.17.1 + github.com/openshift/api v0.0.0-20200331152225-585af27e34fd + github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0 + github.com/operator-framework/api v0.16.0 github.com/operator-framework/operator-registry v1.17.5 github.com/otiai10/copy v1.2.0 github.com/pkg/errors v0.9.1 @@ -221,7 +221,7 @@ require ( golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect @@ -258,6 +258,3 @@ replace ( go.opentelemetry.io/otel => go.opentelemetry.io/otel v0.20.0 go.opentelemetry.io/otel/sdk => go.opentelemetry.io/otel/sdk v0.20.0 ) - -// downstream only -require github.com/openshift/cluster-policy-controller v0.0.0-20220825134653-523e4104074f diff --git a/staging/operator-lifecycle-manager/go.sum b/staging/operator-lifecycle-manager/go.sum index 9a15c91e15..f571581867 100644 --- a/staging/operator-lifecycle-manager/go.sum +++ b/staging/operator-lifecycle-manager/go.sum @@ -1075,13 +1075,11 @@ github.com/openshift/api v0.0.0-20211014063134-be2a7fb8aa44/go.mod h1:RsQCVJu4qh github.com/openshift/build-machinery-go v0.0.0-20210712174854-1bb7fd1518d3/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0 h1:kMiuiZXH1GdfbiMwsuAQOqGaMxlo9NCUk0wT4XAdfNM= github.com/openshift/client-go v0.0.0-20200326155132-2a6cd50aedd0/go.mod h1:uUQ4LClRO+fg5MF/P6QxjMCb1C9f7Oh4RKepftDnEJE= -github.com/openshift/cluster-policy-controller v0.0.0-20220825134653-523e4104074f h1:ll0eE7rgGHsFlrI6ksr6nXL2ur8GYBe8Jj0GwNQ/1+o= -github.com/openshift/cluster-policy-controller v0.0.0-20220825134653-523e4104074f/go.mod h1:r9ZZT5wjwoS2heBfYR26uJhhkGYwgmFqomu9ww0y9Qw= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/operator-framework/api v0.7.1/go.mod h1:L7IvLd/ckxJEJg/t4oTTlnHKAJIP/p51AvEslW3wYdY= -github.com/operator-framework/api v0.17.1 h1:J/6+Xj4IEV8C7hcirqUFwOiZAU3PbnJhWvB0/bB51c4= -github.com/operator-framework/api v0.17.1/go.mod h1:kk8xJahHJR3bKqrA+A+1VIrhOTmyV76k+ARv+iV+u1Q= +github.com/operator-framework/api v0.16.0 h1:swUOhVv7QDszxBTwYM8QAtyeqI4EQHNVAiKMS+xjakY= +github.com/operator-framework/api v0.16.0/go.mod h1:kk8xJahHJR3bKqrA+A+1VIrhOTmyV76k+ARv+iV+u1Q= github.com/operator-framework/operator-registry v1.17.5 h1:LR8m1rFz5Gcyje8WK6iYt+gIhtzqo52zMRALdmTYHT0= github.com/operator-framework/operator-registry v1.17.5/go.mod h1:sRQIgDMZZdUcmHltzyCnM6RUoDF+WS8Arj1BQIARDS8= github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= @@ -1552,9 +1550,8 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go b/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go index f48e62b771..57e283aa68 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go @@ -1,6 +1,7 @@ package install import ( + "context" "fmt" "strconv" "time" @@ -12,6 +13,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/wait" "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs" @@ -42,6 +44,10 @@ const ( // olm managed label OLMManagedLabelKey = "olm.managed" OLMManagedLabelValue = "true" + + // service deletion timeout + serviceDeletionTimeout = 3 * time.Minute + defaultServiceDeletionPollingInterval = 5 * time.Second ) type certResource interface { @@ -260,9 +266,8 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo service.SetOwnerReferences(existingService.GetOwnerReferences()) // Delete the Service to replace - deleteErr := i.strategyClient.GetOpClient().DeleteService(service.GetNamespace(), service.GetName(), &metav1.DeleteOptions{}) - if deleteErr != nil && !apierrors.IsNotFound(deleteErr) { - return nil, nil, fmt.Errorf("could not delete existing service %s", service.GetName()) + if err := i.deleteServiceWithTimeout(service, serviceDeletionTimeout); err != nil { + return nil, nil, err } } @@ -538,6 +543,40 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo return &depSpec, caPEM, nil } +func (i *StrategyDeploymentInstaller) deleteServiceWithTimeout(service *corev1.Service, deletionTimeout time.Duration) error { + timeout, cancelFn := context.WithTimeout(context.Background(), deletionTimeout) + defer cancelFn() + + err := wait.PollImmediateInfiniteWithContext(timeout, i.serviceDeletionPollingInterval, func(ctx context.Context) (bool, error) { + // try to delete service + err := i.strategyClient.GetOpClient().DeleteService(service.GetNamespace(), service.GetName(), &metav1.DeleteOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return true, nil + } + return false, nil + } + + // ensure it is deleted + _, err = i.strategyClient.GetOpClient().GetService(i.owner.GetNamespace(), service.GetName()) + // _, err = i.strategyClient.GetOpLister().CoreV1().ServiceLister().Services(i.owner.GetNamespace()).Get(service.GetName()) + + // successfully deleted + if err != nil && apierrors.IsNotFound(err) { + return true, nil + } + + // otherwise, try again... + return false, nil + }) + + if err != nil { + return fmt.Errorf("manual intervention required: unable to delete existing service %s within timeout period %s", service.GetName(), deletionTimeout) + } + + return nil +} + func SetCAAnnotation(depSpec *appsv1.DeploymentSpec, caHash string) { if len(depSpec.Template.ObjectMeta.GetAnnotations()) == 0 { depSpec.Template.ObjectMeta.SetAnnotations(map[string]string{OLMCAHashAnnotationKey: caHash}) diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go b/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go index 3823f29f37..ebb551dea4 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/certresources_test.go @@ -165,6 +165,7 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { Selector: selector(t, "test=label").MatchLabels, }, } + mockOpClient.EXPECT().GetService("", "test-service").Return(nil, errors.NewNotFound(corev1.Resource("service"), "test-service")) mockOpClient.EXPECT().CreateService(&service).Return(&service, nil) hosts := []string{ @@ -389,6 +390,8 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { Selector: selector(t, "test=label").MatchLabels, }, } + + mockOpClient.EXPECT().GetService(namespace, "test-service").Return(nil, errors.NewNotFound(corev1.Resource("service"), "test-service")) mockOpClient.EXPECT().CreateService(&service).Return(&service, nil) hosts := []string{ @@ -606,6 +609,8 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { Selector: selector(t, "test=label").MatchLabels, }, } + + mockOpClient.EXPECT().GetService(namespace, "test-service").Return(nil, errors.NewNotFound(corev1.Resource("service"), "test-service")) mockOpClient.EXPECT().CreateService(&service).Return(&service, nil) hosts := []string{ @@ -825,6 +830,239 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { }, }, }, + { + name: "retries deletion if service is still present", + mockExternal: func(mockOpClient *operatorclientmocks.MockClientInterface, fakeLister *operatorlisterfakes.FakeOperatorLister, namespace string, args args) { + mockOpClient.EXPECT().DeleteService(namespace, "test-service", &metav1.DeleteOptions{}).Return(nil) + service := corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-service", + OwnerReferences: []metav1.OwnerReference{ + ownerutil.NonBlockingOwner(&v1alpha1.ClusterServiceVersion{}), + }, + }, + Spec: corev1.ServiceSpec{ + Ports: args.ports, + Selector: selector(t, "test=label").MatchLabels, + }, + } + mockOpClient.EXPECT().GetService(namespace, "test-service").Return(&service, nil) + + // retry + mockOpClient.EXPECT().DeleteService(namespace, "test-service", &metav1.DeleteOptions{}).Return(nil) + mockOpClient.EXPECT().GetService(namespace, "test-service").Return(&service, nil) + mockOpClient.EXPECT().DeleteService(namespace, "test-service", &metav1.DeleteOptions{}).Return(nil) + + // done + mockOpClient.EXPECT().GetService(namespace, "test-service").Return(nil, errors.NewNotFound(corev1.Resource("service"), "test-service")) + + mockOpClient.EXPECT().CreateService(&service).Return(&service, nil) + + hosts := []string{ + fmt.Sprintf("%s.%s", service.GetName(), namespace), + fmt.Sprintf("%s.%s.svc", service.GetName(), namespace), + } + servingPair, err := certGenerator.Generate(args.rotateAt, Organization, args.ca, hosts) + require.NoError(t, err) + + // Create Secret for serving cert + certPEM, privPEM, err := servingPair.ToPEM() + require.NoError(t, err) + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-service-cert", + Namespace: namespace, + Annotations: map[string]string{OLMCAHashAnnotationKey: caHash}, + Labels: map[string]string{OLMManagedLabelKey: OLMManagedLabelValue}, + }, + Data: map[string][]byte{ + "tls.crt": certPEM, + "tls.key": privPEM, + OLMCAPEMKey: caPEM, + }, + Type: corev1.SecretTypeTLS, + } + mockOpClient.EXPECT().UpdateSecret(secret).Return(secret, nil) + + secretRole := &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: secret.GetName(), + Namespace: namespace, + }, + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"get"}, + APIGroups: []string{""}, + Resources: []string{"secrets"}, + ResourceNames: []string{secret.GetName()}, + }, + }, + } + mockOpClient.EXPECT().UpdateRole(secretRole).Return(secretRole, nil) + + roleBinding := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: secret.GetName(), + Namespace: namespace, + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + APIGroup: "", + Name: "test-sa", + Namespace: namespace, + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: secretRole.GetName(), + }, + } + mockOpClient.EXPECT().UpdateRoleBinding(roleBinding).Return(roleBinding, nil) + + authDelegatorClusterRoleBinding := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: service.GetName() + "-system:auth-delegator", + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + APIGroup: "", + Name: "test-sa", + Namespace: namespace, + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "system:auth-delegator", + }, + } + + mockOpClient.EXPECT().UpdateClusterRoleBinding(authDelegatorClusterRoleBinding).Return(authDelegatorClusterRoleBinding, nil) + + authReaderRoleBinding := &rbacv1.RoleBinding{ + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + APIGroup: "", + Name: args.depSpec.Template.Spec.ServiceAccountName, + Namespace: namespace, + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "extension-apiserver-authentication-reader", + }, + } + authReaderRoleBinding.SetName(service.GetName() + "-auth-reader") + authReaderRoleBinding.SetNamespace(KubeSystem) + + mockOpClient.EXPECT().UpdateRoleBinding(authReaderRoleBinding).Return(authReaderRoleBinding, nil) + }, + state: fakeState{ + existingService: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{ + ownerutil.NonBlockingOwner(&v1alpha1.ClusterServiceVersion{}), + }, + }, + }, + existingSecret: &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{}, + }, + existingRole: &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{}, + }, + existingRoleBinding: &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{}, + }, + existingClusterRoleBinding: &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{}, + }, + }, + fields: fields{ + owner: &v1alpha1.ClusterServiceVersion{}, + previousStrategy: nil, + templateAnnotations: nil, + initializers: nil, + apiServiceDescriptions: []certResource{}, + webhookDescriptions: []certResource{}, + }, + args: args{ + deploymentName: "test", + ca: ca, + rotateAt: time.Now().Add(time.Hour), + ports: []corev1.ServicePort{}, + depSpec: appsv1.DeploymentSpec{ + Selector: selector(t, "test=label"), + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + ServiceAccountName: "test-sa", + }, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + }, + want: &appsv1.DeploymentSpec{ + Selector: selector(t, "test=label"), + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "foo": "bar", + OLMCAHashAnnotationKey: caHash}, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: "test-sa", + Volumes: []corev1.Volume{ + { + Name: "apiservice-cert", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "test-service-cert", + Items: []corev1.KeyToPath{ + { + Key: "tls.crt", + Path: "apiserver.crt", + }, + { + Key: "tls.key", + Path: "apiserver.key", + }, + }, + }, + }, + }, + { + Name: "webhook-cert", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "test-service-cert", + Items: []corev1.KeyToPath{ + { + Key: "tls.crt", + Path: "tls.crt", + }, + { + Key: "tls.key", + Path: "tls.key", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -839,13 +1077,14 @@ func TestInstallCertRequirementsForDeployment(t *testing.T) { client := wrappers.NewInstallStrategyDeploymentClient(mockOpClient, fakeLister, tt.fields.owner.GetNamespace()) i := &StrategyDeploymentInstaller{ - strategyClient: client, - owner: tt.fields.owner, - previousStrategy: tt.fields.previousStrategy, - templateAnnotations: tt.fields.templateAnnotations, - initializers: tt.fields.initializers, - apiServiceDescriptions: tt.fields.apiServiceDescriptions, - webhookDescriptions: tt.fields.webhookDescriptions, + strategyClient: client, + owner: tt.fields.owner, + previousStrategy: tt.fields.previousStrategy, + templateAnnotations: tt.fields.templateAnnotations, + initializers: tt.fields.initializers, + apiServiceDescriptions: tt.fields.apiServiceDescriptions, + webhookDescriptions: tt.fields.webhookDescriptions, + serviceDeletionPollingInterval: shortDeletionPollingInterval, } got, _, err := i.installCertRequirementsForDeployment(tt.args.deploymentName, tt.args.ca, tt.args.rotateAt, tt.args.depSpec, tt.args.ports) if (err != nil) != tt.wantErr { diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go b/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go index 559520aad7..81538d601b 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go @@ -23,15 +23,16 @@ import ( const DeploymentSpecHashLabelKey = "olm.deployment-spec-hash" type StrategyDeploymentInstaller struct { - strategyClient wrappers.InstallStrategyDeploymentInterface - owner ownerutil.Owner - previousStrategy Strategy - templateAnnotations map[string]string - initializers DeploymentInitializerFuncChain - apiServiceDescriptions []certResource - webhookDescriptions []certResource - certificateExpirationTime time.Time - certificatesRotated bool + strategyClient wrappers.InstallStrategyDeploymentInterface + owner ownerutil.Owner + previousStrategy Strategy + templateAnnotations map[string]string + initializers DeploymentInitializerFuncChain + apiServiceDescriptions []certResource + webhookDescriptions []certResource + certificateExpirationTime time.Time + certificatesRotated bool + serviceDeletionPollingInterval time.Duration } var _ Strategy = &v1alpha1.StrategyDetailsDeployment{} @@ -68,7 +69,7 @@ func (c DeploymentInitializerFuncChain) Apply(deployment *appsv1.Deployment) (er // the given context. type DeploymentInitializerBuilderFunc func(owner ownerutil.Owner) DeploymentInitializerFunc -func NewStrategyDeploymentInstaller(strategyClient wrappers.InstallStrategyDeploymentInterface, templateAnnotations map[string]string, owner ownerutil.Owner, previousStrategy Strategy, initializers DeploymentInitializerFuncChain, apiServiceDescriptions []v1alpha1.APIServiceDescription, webhookDescriptions []v1alpha1.WebhookDescription) StrategyInstaller { +func NewStrategyDeploymentInstaller(strategyClient wrappers.InstallStrategyDeploymentInterface, templateAnnotations map[string]string, owner ownerutil.Owner, previousStrategy Strategy, initializers DeploymentInitializerFuncChain, apiServiceDescriptions []v1alpha1.APIServiceDescription, webhookDescriptions []v1alpha1.WebhookDescription, serviceDeletionPollingInterval time.Duration) StrategyInstaller { apiDescs := make([]certResource, len(apiServiceDescriptions)) for i := range apiServiceDescriptions { apiDescs[i] = &apiServiceDescriptionsWithCAPEM{apiServiceDescriptions[i], []byte{}} @@ -80,15 +81,16 @@ func NewStrategyDeploymentInstaller(strategyClient wrappers.InstallStrategyDeplo } return &StrategyDeploymentInstaller{ - strategyClient: strategyClient, - owner: owner, - previousStrategy: previousStrategy, - templateAnnotations: templateAnnotations, - initializers: initializers, - apiServiceDescriptions: apiDescs, - webhookDescriptions: webhookDescs, - certificatesRotated: false, - certificateExpirationTime: time.Time{}, + strategyClient: strategyClient, + owner: owner, + previousStrategy: previousStrategy, + templateAnnotations: templateAnnotations, + initializers: initializers, + apiServiceDescriptions: apiDescs, + webhookDescriptions: webhookDescs, + certificatesRotated: false, + certificateExpirationTime: time.Time{}, + serviceDeletionPollingInterval: serviceDeletionPollingInterval, } } diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/deployment_test.go b/staging/operator-lifecycle-manager/pkg/controller/install/deployment_test.go index d9ec66cc2a..c1424cb014 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/deployment_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/deployment_test.go @@ -3,6 +3,7 @@ package install import ( "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -18,6 +19,9 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" ) +// shorten deployment strategy installer service deletion polling interval +const shortDeletionPollingInterval = 50 * time.Millisecond + func testDeployment(name, namespace string, mockOwner ownerutil.Owner) appsv1.Deployment { testDeploymentLabels := map[string]string{"olm.owner": mockOwner.GetName(), "olm.owner.namespace": mockOwner.GetNamespace(), "olm.owner.kind": "ClusterServiceVersion"} @@ -308,7 +312,7 @@ func TestNewStrategyDeploymentInstaller(t *testing.T) { }, } fakeClient := new(clientfakes.FakeInstallStrategyDeploymentInterface) - strategy := NewStrategyDeploymentInstaller(fakeClient, map[string]string{"test": "annotation"}, &mockOwner, nil, nil, nil, nil) + strategy := NewStrategyDeploymentInstaller(fakeClient, map[string]string{"test": "annotation"}, &mockOwner, nil, nil, nil, nil, shortDeletionPollingInterval) require.Implements(t, (*StrategyInstaller)(nil), strategy) require.Error(t, strategy.Install(&BadStrategy{})) installed, err := strategy.CheckInstalled(&BadStrategy{}) @@ -347,7 +351,7 @@ func TestInstallStrategyDeploymentCheckInstallErrors(t *testing.T) { t.Run(tt.description, func(t *testing.T) { fakeClient := new(clientfakes.FakeInstallStrategyDeploymentInterface) strategy := strategy(1, namespace, &mockOwner) - installer := NewStrategyDeploymentInstaller(fakeClient, map[string]string{"test": "annotation"}, &mockOwner, nil, nil, nil, nil) + installer := NewStrategyDeploymentInstaller(fakeClient, map[string]string{"test": "annotation"}, &mockOwner, nil, nil, nil, nil, shortDeletionPollingInterval) dep := testDeployment("olm-dep-1", namespace, &mockOwner) dep.Spec.Template.SetAnnotations(map[string]string{"test": "annotation"}) diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/resolver.go b/staging/operator-lifecycle-manager/pkg/controller/install/resolver.go index 206ce9e384..1a15f6b2aa 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/resolver.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/resolver.go @@ -53,7 +53,7 @@ func (r *StrategyResolver) InstallerForStrategy(strategyName string, opClient op initializers = append(initializers, r.OverridesBuilderFunc(owner)) } - return NewStrategyDeploymentInstaller(strategyClient, annotations, owner, previousStrategy, initializers, apiServiceDescriptions, webhookDescriptions) + return NewStrategyDeploymentInstaller(strategyClient, annotations, owner, previousStrategy, initializers, apiServiceDescriptions, webhookDescriptions, defaultServiceDeletionPollingInterval) } // Insurance against these functions being called incorrectly (unmarshal strategy will return a valid strategy name) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator_test.go index 51b07250c7..8c46883bed 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator_test.go @@ -5,8 +5,8 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "math/rand" + "os" "reflect" "strings" "testing" @@ -1353,7 +1353,7 @@ func TestCompetingCRDOwnersExist(t *testing.T) { func TestValidateExistingCRs(t *testing.T) { unstructuredForFile := func(file string) *unstructured.Unstructured { - data, err := ioutil.ReadFile(file) + data, err := os.ReadFile(file) require.NoError(t, err) dec := utilyaml.NewYAMLOrJSONDecoder(strings.NewReader(string(data)), 30) k8sFile := &unstructured.Unstructured{} @@ -1362,7 +1362,7 @@ func TestValidateExistingCRs(t *testing.T) { } unversionedCRDForV1beta1File := func(file string) *apiextensions.CustomResourceDefinition { - data, err := ioutil.ReadFile(file) + data, err := os.ReadFile(file) require.NoError(t, err) dec := utilyaml.NewYAMLOrJSONDecoder(strings.NewReader(string(data)), 30) k8sFile := &apiextensionsv1beta1.CustomResourceDefinition{} @@ -1744,7 +1744,7 @@ func objectReference(name string) *corev1.ObjectReference { } func yamlFromFilePath(t *testing.T, fileName string) string { - yaml, err := ioutil.ReadFile(fileName) + yaml, err := os.ReadFile(fileName) require.NoError(t, err) return string(yaml) diff --git a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go index 4fcee4e457..58f577ef45 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go +++ b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go @@ -2,7 +2,7 @@ package filemonitor import ( "crypto/x509" - "io/ioutil" + "os" "sync" "github.com/fsnotify/fsnotify" @@ -16,7 +16,7 @@ type certPoolStore struct { } func NewCertPoolStore(clientCAPath string) (*certPoolStore, error) { - pem, err := ioutil.ReadFile(clientCAPath) + pem, err := os.ReadFile(clientCAPath) if err != nil { return nil, err } @@ -31,7 +31,7 @@ func NewCertPoolStore(clientCAPath string) (*certPoolStore, error) { } func (c *certPoolStore) storeCABundle(clientCAPath string) error { - pem, err := ioutil.ReadFile(clientCAPath) + pem, err := os.ReadFile(clientCAPath) if err == nil { c.mutex.Lock() defer c.mutex.Unlock() diff --git a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater_test.go b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater_test.go index 022b22fc30..039e5ceac2 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater_test.go +++ b/staging/operator-lifecycle-manager/pkg/lib/filemonitor/cert_updater_test.go @@ -6,7 +6,6 @@ import ( "crypto/x509" "fmt" "html" - "io/ioutil" "net" "net/http" "os" @@ -88,7 +87,7 @@ func TestOLMGetCertRotationFn(t *testing.T) { } }() - caCert, err := ioutil.ReadFile(caCrt) + caCert, err := os.ReadFile(caCrt) require.NoError(t, err) caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) diff --git a/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go b/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go index 058f3f4017..d3dbcee5db 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go +++ b/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go @@ -82,6 +82,12 @@ func getAPISecret(logger logrus.FieldLogger, kubeclient operatorclient.ClientInt func filterSecretsBySAName(saName string, secrets *corev1.SecretList) map[string]*corev1.Secret { secretMap := make(map[string]*corev1.Secret) for _, ref := range secrets.Items { + // Avoid referencing the "ref" created by the range-for loop as + // the secret stored in the map will change if there are more + // entries in the list of secrets that the range-for loop is + // iterating over. + ref := ref + annotations := ref.GetAnnotations() value := annotations[corev1.ServiceAccountNameKey] if value == saName { diff --git a/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever_test.go b/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever_test.go new file mode 100644 index 0000000000..c3a514035c --- /dev/null +++ b/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever_test.go @@ -0,0 +1,117 @@ +package scoped + +import ( + "testing" + + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const serviceAccountName = "foo" + +func TestFilterSecretsBySAName(t *testing.T) { + tests := []struct { + name string + secrets *corev1.SecretList + wantedSecretNames []string + }{ + { + name: "NoSecretFound", + secrets: &corev1.SecretList{ + Items: []corev1.Secret{ + *newSecret("aSecret"), + *newSecret("someSecret"), + *newSecret("zSecret"), + }, + }, + wantedSecretNames: []string{}, + }, + { + name: "FirstSecretFound", + secrets: &corev1.SecretList{ + Items: []corev1.Secret{ + *newSecret("aSecret", withAnnotations(map[string]string{corev1.ServiceAccountNameKey: serviceAccountName})), + *newSecret("someSecret"), + *newSecret("zSecret"), + }, + }, + wantedSecretNames: []string{"aSecret"}, + }, + { + name: "SecondSecretFound", + secrets: &corev1.SecretList{ + Items: []corev1.Secret{ + *newSecret("aSecret"), + *newSecret("someSecret", withAnnotations(map[string]string{corev1.ServiceAccountNameKey: serviceAccountName})), + *newSecret("zSecret"), + }, + }, + wantedSecretNames: []string{"someSecret"}, + }, + { + name: "ThirdSecretFound", + secrets: &corev1.SecretList{ + Items: []corev1.Secret{ + *newSecret("aSecret"), + *newSecret("someSecret"), + *newSecret("zSecret", withAnnotations(map[string]string{corev1.ServiceAccountNameKey: serviceAccountName})), + }, + }, + wantedSecretNames: []string{"zSecret"}, + }, + { + name: "TwoSecretsFound", + secrets: &corev1.SecretList{ + Items: []corev1.Secret{ + *newSecret("aSecret"), + *newSecret("someSecret", withAnnotations(map[string]string{corev1.ServiceAccountNameKey: serviceAccountName})), + *newSecret("zSecret", withAnnotations(map[string]string{corev1.ServiceAccountNameKey: serviceAccountName})), + }, + }, + wantedSecretNames: []string{"someSecret", "zSecret"}, + }, + { + name: "AllSecretsFound", + secrets: &corev1.SecretList{ + Items: []corev1.Secret{ + *newSecret("aSecret", withAnnotations(map[string]string{corev1.ServiceAccountNameKey: serviceAccountName})), + *newSecret("someSecret", withAnnotations(map[string]string{corev1.ServiceAccountNameKey: serviceAccountName})), + *newSecret("zSecret", withAnnotations(map[string]string{corev1.ServiceAccountNameKey: serviceAccountName})), + }, + }, + wantedSecretNames: []string{"aSecret", "someSecret", "zSecret"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := filterSecretsBySAName(serviceAccountName, tt.secrets) + require.Equal(t, len(tt.wantedSecretNames), len(got)) + for _, wantedSecretName := range tt.wantedSecretNames { + require.NotNil(t, got[wantedSecretName]) + require.Equal(t, wantedSecretName, got[wantedSecretName].GetName()) + } + }) + } +} + +type secretOption func(*corev1.Secret) + +func withAnnotations(annotations map[string]string) secretOption { + return func(s *corev1.Secret) { + s.SetAnnotations(annotations) + } +} + +func newSecret(name string, opts ...secretOption) *corev1.Secret { + s := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + } + for _, opt := range opts { + opt(s) + } + return s +} diff --git a/staging/operator-lifecycle-manager/pkg/package-server/provider/test.db b/staging/operator-lifecycle-manager/pkg/package-server/provider/test.db new file mode 100644 index 0000000000..e69de29bb2 diff --git a/staging/operator-lifecycle-manager/pkg/package-server/provider/test.db-journal b/staging/operator-lifecycle-manager/pkg/package-server/provider/test.db-journal new file mode 100644 index 0000000000..3bd04a0661 Binary files /dev/null and b/staging/operator-lifecycle-manager/pkg/package-server/provider/test.db-journal differ diff --git a/staging/operator-lifecycle-manager/pkg/package-server/storage/subresources.go b/staging/operator-lifecycle-manager/pkg/package-server/storage/subresources.go index 45d30bd59b..455da45dc6 100644 --- a/staging/operator-lifecycle-manager/pkg/package-server/storage/subresources.go +++ b/staging/operator-lifecycle-manager/pkg/package-server/storage/subresources.go @@ -3,7 +3,7 @@ package storage import ( "context" "encoding/base64" - "io/ioutil" + "io" "net/http" "strconv" "strings" @@ -68,7 +68,7 @@ func (s *LogoStorage) Connect(ctx context.Context, name string, options runtime. etag := `"` + strings.Join([]string{name, pkgChannel.Name, pkgChannel.CurrentCSV}, ".") + `"` reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(data)) - imgBytes, _ := ioutil.ReadAll(reader) + imgBytes, _ := io.ReadAll(reader) return imgBytes, mimeType, etag } diff --git a/staging/operator-lifecycle-manager/test/e2e/ctx/provisioner_kind.go b/staging/operator-lifecycle-manager/test/e2e/ctx/provisioner_kind.go index 27f6d7c78c..6ac0ab976c 100644 --- a/staging/operator-lifecycle-manager/test/e2e/ctx/provisioner_kind.go +++ b/staging/operator-lifecycle-manager/test/e2e/ctx/provisioner_kind.go @@ -7,7 +7,6 @@ import ( "encoding/csv" "flag" "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -78,7 +77,7 @@ func (kl kindLogAdapter) V(level log.Level) log.InfoLogger { } func Provision(ctx *TestContext) (func(), error) { - dir, err := ioutil.TempDir("", "kind.") + dir, err := os.MkdirTemp("", "kind.") if err != nil { return nil, fmt.Errorf("failed to create temporary directory: %s", err.Error()) } diff --git a/staging/operator-lifecycle-manager/test/e2e/setup_bare_test.go b/staging/operator-lifecycle-manager/test/e2e/setup_bare_test.go index 354e41cf68..f21ae71a98 100644 --- a/staging/operator-lifecycle-manager/test/e2e/setup_bare_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/setup_bare_test.go @@ -7,7 +7,6 @@ import ( "context" "flag" "io" - "io/ioutil" "os" "strings" "testing" @@ -65,7 +64,7 @@ func TestMain(m *testing.M) { testNamespace = *namespace if testNamespace == "" { - testNamespaceBytes, err := ioutil.ReadFile("e2e.namespace") + testNamespaceBytes, err := os.ReadFile("e2e.namespace") if err != nil || testNamespaceBytes == nil { panic("no namespace set") } diff --git a/staging/operator-lifecycle-manager/test/e2e/split/main.go b/staging/operator-lifecycle-manager/test/e2e/split/main.go index 30745d0cab..1637fdb567 100644 --- a/staging/operator-lifecycle-manager/test/e2e/split/main.go +++ b/staging/operator-lifecycle-manager/test/e2e/split/main.go @@ -4,7 +4,6 @@ import ( "flag" "fmt" "io" - "io/ioutil" "log" "math" "os" @@ -106,7 +105,7 @@ func findDescribes(logger logrus.FieldLogger, dir string) ([]string, error) { return nil, err } for _, match := range matches { - b, err := ioutil.ReadFile(match) + b, err := os.ReadFile(match) if err != nil { return nil, err } diff --git a/staging/operator-lifecycle-manager/util/cpb/main.go b/staging/operator-lifecycle-manager/util/cpb/main.go index ae9912bf97..5b1769bb37 100644 --- a/staging/operator-lifecycle-manager/util/cpb/main.go +++ b/staging/operator-lifecycle-manager/util/cpb/main.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "io/ioutil" "os" "path/filepath" @@ -118,7 +117,7 @@ func getMetadata() (m *metadata, err error) { m.annotationsFile = path // Unmarshal metadata - content, err := ioutil.ReadFile(path) + content, err := os.ReadFile(path) if err != nil { return fmt.Errorf("couldn't get content of annotations.yaml file: %s", path) } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go index f48e62b771..57e283aa68 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/certresources.go @@ -1,6 +1,7 @@ package install import ( + "context" "fmt" "strconv" "time" @@ -12,6 +13,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/wait" "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs" @@ -42,6 +44,10 @@ const ( // olm managed label OLMManagedLabelKey = "olm.managed" OLMManagedLabelValue = "true" + + // service deletion timeout + serviceDeletionTimeout = 3 * time.Minute + defaultServiceDeletionPollingInterval = 5 * time.Second ) type certResource interface { @@ -260,9 +266,8 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo service.SetOwnerReferences(existingService.GetOwnerReferences()) // Delete the Service to replace - deleteErr := i.strategyClient.GetOpClient().DeleteService(service.GetNamespace(), service.GetName(), &metav1.DeleteOptions{}) - if deleteErr != nil && !apierrors.IsNotFound(deleteErr) { - return nil, nil, fmt.Errorf("could not delete existing service %s", service.GetName()) + if err := i.deleteServiceWithTimeout(service, serviceDeletionTimeout); err != nil { + return nil, nil, err } } @@ -538,6 +543,40 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo return &depSpec, caPEM, nil } +func (i *StrategyDeploymentInstaller) deleteServiceWithTimeout(service *corev1.Service, deletionTimeout time.Duration) error { + timeout, cancelFn := context.WithTimeout(context.Background(), deletionTimeout) + defer cancelFn() + + err := wait.PollImmediateInfiniteWithContext(timeout, i.serviceDeletionPollingInterval, func(ctx context.Context) (bool, error) { + // try to delete service + err := i.strategyClient.GetOpClient().DeleteService(service.GetNamespace(), service.GetName(), &metav1.DeleteOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return true, nil + } + return false, nil + } + + // ensure it is deleted + _, err = i.strategyClient.GetOpClient().GetService(i.owner.GetNamespace(), service.GetName()) + // _, err = i.strategyClient.GetOpLister().CoreV1().ServiceLister().Services(i.owner.GetNamespace()).Get(service.GetName()) + + // successfully deleted + if err != nil && apierrors.IsNotFound(err) { + return true, nil + } + + // otherwise, try again... + return false, nil + }) + + if err != nil { + return fmt.Errorf("manual intervention required: unable to delete existing service %s within timeout period %s", service.GetName(), deletionTimeout) + } + + return nil +} + func SetCAAnnotation(depSpec *appsv1.DeploymentSpec, caHash string) { if len(depSpec.Template.ObjectMeta.GetAnnotations()) == 0 { depSpec.Template.ObjectMeta.SetAnnotations(map[string]string{OLMCAHashAnnotationKey: caHash}) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/deployment.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/deployment.go index 559520aad7..81538d601b 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/deployment.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/deployment.go @@ -23,15 +23,16 @@ import ( const DeploymentSpecHashLabelKey = "olm.deployment-spec-hash" type StrategyDeploymentInstaller struct { - strategyClient wrappers.InstallStrategyDeploymentInterface - owner ownerutil.Owner - previousStrategy Strategy - templateAnnotations map[string]string - initializers DeploymentInitializerFuncChain - apiServiceDescriptions []certResource - webhookDescriptions []certResource - certificateExpirationTime time.Time - certificatesRotated bool + strategyClient wrappers.InstallStrategyDeploymentInterface + owner ownerutil.Owner + previousStrategy Strategy + templateAnnotations map[string]string + initializers DeploymentInitializerFuncChain + apiServiceDescriptions []certResource + webhookDescriptions []certResource + certificateExpirationTime time.Time + certificatesRotated bool + serviceDeletionPollingInterval time.Duration } var _ Strategy = &v1alpha1.StrategyDetailsDeployment{} @@ -68,7 +69,7 @@ func (c DeploymentInitializerFuncChain) Apply(deployment *appsv1.Deployment) (er // the given context. type DeploymentInitializerBuilderFunc func(owner ownerutil.Owner) DeploymentInitializerFunc -func NewStrategyDeploymentInstaller(strategyClient wrappers.InstallStrategyDeploymentInterface, templateAnnotations map[string]string, owner ownerutil.Owner, previousStrategy Strategy, initializers DeploymentInitializerFuncChain, apiServiceDescriptions []v1alpha1.APIServiceDescription, webhookDescriptions []v1alpha1.WebhookDescription) StrategyInstaller { +func NewStrategyDeploymentInstaller(strategyClient wrappers.InstallStrategyDeploymentInterface, templateAnnotations map[string]string, owner ownerutil.Owner, previousStrategy Strategy, initializers DeploymentInitializerFuncChain, apiServiceDescriptions []v1alpha1.APIServiceDescription, webhookDescriptions []v1alpha1.WebhookDescription, serviceDeletionPollingInterval time.Duration) StrategyInstaller { apiDescs := make([]certResource, len(apiServiceDescriptions)) for i := range apiServiceDescriptions { apiDescs[i] = &apiServiceDescriptionsWithCAPEM{apiServiceDescriptions[i], []byte{}} @@ -80,15 +81,16 @@ func NewStrategyDeploymentInstaller(strategyClient wrappers.InstallStrategyDeplo } return &StrategyDeploymentInstaller{ - strategyClient: strategyClient, - owner: owner, - previousStrategy: previousStrategy, - templateAnnotations: templateAnnotations, - initializers: initializers, - apiServiceDescriptions: apiDescs, - webhookDescriptions: webhookDescs, - certificatesRotated: false, - certificateExpirationTime: time.Time{}, + strategyClient: strategyClient, + owner: owner, + previousStrategy: previousStrategy, + templateAnnotations: templateAnnotations, + initializers: initializers, + apiServiceDescriptions: apiDescs, + webhookDescriptions: webhookDescs, + certificatesRotated: false, + certificateExpirationTime: time.Time{}, + serviceDeletionPollingInterval: serviceDeletionPollingInterval, } } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/resolver.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/resolver.go index 206ce9e384..1a15f6b2aa 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/resolver.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install/resolver.go @@ -53,7 +53,7 @@ func (r *StrategyResolver) InstallerForStrategy(strategyName string, opClient op initializers = append(initializers, r.OverridesBuilderFunc(owner)) } - return NewStrategyDeploymentInstaller(strategyClient, annotations, owner, previousStrategy, initializers, apiServiceDescriptions, webhookDescriptions) + return NewStrategyDeploymentInstaller(strategyClient, annotations, owner, previousStrategy, initializers, apiServiceDescriptions, webhookDescriptions, defaultServiceDeletionPollingInterval) } // Insurance against these functions being called incorrectly (unmarshal strategy will return a valid strategy name) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go index 4fcee4e457..58f577ef45 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor/cabundle_updater.go @@ -2,7 +2,7 @@ package filemonitor import ( "crypto/x509" - "io/ioutil" + "os" "sync" "github.com/fsnotify/fsnotify" @@ -16,7 +16,7 @@ type certPoolStore struct { } func NewCertPoolStore(clientCAPath string) (*certPoolStore, error) { - pem, err := ioutil.ReadFile(clientCAPath) + pem, err := os.ReadFile(clientCAPath) if err != nil { return nil, err } @@ -31,7 +31,7 @@ func NewCertPoolStore(clientCAPath string) (*certPoolStore, error) { } func (c *certPoolStore) storeCABundle(clientCAPath string) error { - pem, err := ioutil.ReadFile(clientCAPath) + pem, err := os.ReadFile(clientCAPath) if err == nil { c.mutex.Lock() defer c.mutex.Unlock() diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go index 058f3f4017..d3dbcee5db 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go @@ -82,6 +82,12 @@ func getAPISecret(logger logrus.FieldLogger, kubeclient operatorclient.ClientInt func filterSecretsBySAName(saName string, secrets *corev1.SecretList) map[string]*corev1.Secret { secretMap := make(map[string]*corev1.Secret) for _, ref := range secrets.Items { + // Avoid referencing the "ref" created by the range-for loop as + // the secret stored in the map will change if there are more + // entries in the list of secrets that the range-for loop is + // iterating over. + ref := ref + annotations := ref.GetAnnotations() value := annotations[corev1.ServiceAccountNameKey] if value == saName { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/storage/subresources.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/storage/subresources.go index 45d30bd59b..455da45dc6 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/storage/subresources.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/storage/subresources.go @@ -3,7 +3,7 @@ package storage import ( "context" "encoding/base64" - "io/ioutil" + "io" "net/http" "strconv" "strings" @@ -68,7 +68,7 @@ func (s *LogoStorage) Connect(ctx context.Context, name string, options runtime. etag := `"` + strings.Join([]string{name, pkgChannel.Name, pkgChannel.CurrentCSV}, ".") + `"` reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(data)) - imgBytes, _ := ioutil.ReadAll(reader) + imgBytes, _ := io.ReadAll(reader) return imgBytes, mimeType, etag } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/util/cpb/main.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/util/cpb/main.go index ae9912bf97..5b1769bb37 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/util/cpb/main.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/util/cpb/main.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "io/ioutil" "os" "path/filepath" @@ -118,7 +117,7 @@ func getMetadata() (m *metadata, err error) { m.annotationsFile = path // Unmarshal metadata - content, err := ioutil.ReadFile(path) + content, err := os.ReadFile(path) if err != nil { return fmt.Errorf("couldn't get content of annotations.yaml file: %s", path) }