diff --git a/api/v1alpha1/imagerepository_types.go b/api/v1alpha1/imagerepository_types.go index 8189044..ae5d53c 100644 --- a/api/v1alpha1/imagerepository_types.go +++ b/api/v1alpha1/imagerepository_types.go @@ -156,13 +156,6 @@ type CredentialsStatus struct { // PullRobotAccountName is present only if ImageRepository has labels that connect it to Application and Component. // Holds name of the quay robot account with real (pull only) permissions from the generated repository. PullRobotAccountName string `json:"pull-robot-account,omitempty"` - - // PushRemoteSecretName holds name of RemoteSecret object that manages push Secret and its linking to appstudio-pipeline Service Account. - PushRemoteSecretName string `json:"push-remote-secret,omitempty"` - - // PullRemoteSecretName is present only if ImageRepository has labels that connect it to Application and Component. - // Holds the name of the RemoteSecret object that manages pull Secret. - PullRemoteSecretName string `json:"pull-remote-secret,omitempty"` } // NotificationStatus shows the status of the notification configuration. diff --git a/config/crd/bases/appstudio.redhat.com_imagerepositories.yaml b/config/crd/bases/appstudio.redhat.com_imagerepositories.yaml index 44cf54a..6d14fb1 100644 --- a/config/crd/bases/appstudio.redhat.com_imagerepositories.yaml +++ b/config/crd/bases/appstudio.redhat.com_imagerepositories.yaml @@ -110,11 +110,6 @@ spec: were generated. format: date-time type: string - pull-remote-secret: - description: PullRemoteSecretName is present only if ImageRepository - has labels that connect it to Application and Component. Holds - the name of the RemoteSecret object that manages pull Secret. - type: string pull-robot-account: description: PullRobotAccountName is present only if ImageRepository has labels that connect it to Application and Component. Holds @@ -129,11 +124,6 @@ spec: in the same namespace as ImageRepository, but created in other environments. type: string - push-remote-secret: - description: PushRemoteSecretName holds name of RemoteSecret object - that manages push Secret and its linking to appstudio-pipeline - Service Account. - type: string push-robot-account: description: PushRobotAccountName holds name of the quay robot account with write (push and pull) permissions into the generated diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 69fbd26..7eaebd3 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -53,12 +53,4 @@ rules: - get - patch - update -- apiGroups: - - appstudio.redhat.com - resources: - - remotesecrets - verbs: - - create - - get - - list - - watch + diff --git a/controllers/component_image_controller.go b/controllers/component_image_controller.go index 852b966..bb55ac1 100644 --- a/controllers/component_image_controller.go +++ b/controllers/component_image_controller.go @@ -39,7 +39,6 @@ import ( "github.com/konflux-ci/image-controller/pkg/metrics" "github.com/konflux-ci/image-controller/pkg/quay" appstudioredhatcomv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" - remotesecretv1beta1 "github.com/redhat-appstudio/remote-secret/api/v1beta1" ) const ( @@ -50,8 +49,6 @@ const ( ApplicationNameLabelName = "appstudio.redhat.com/application" ComponentNameLabelName = "appstudio.redhat.com/component" - - defaultServiceAccountName = "default" ) // GenerateRepositoryOpts defines patameters for image repository to be generated. @@ -263,10 +260,7 @@ func (r *ComponentReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( // Propagate the pull secret into all environments pullSecretName := pushSecretName + "-pull" - if err := r.ensureComponentPullSecretRemoteSecret(ctx, component, pullSecretName); err != nil { - return ctrl.Result{}, err - } - if err := r.createRemoteSecretUploadSecret(ctx, pullRobotAccount, component.Namespace, pullSecretName, imageURL); err != nil { + if err := r.ensureComponentPullSecret(ctx, component, pullSecretName, pullRobotAccount, imageURL); err != nil { return ctrl.Result{}, err } log.Info(fmt.Sprintf("Prepared remote secret %s for Component", pullSecretName), l.Action, l.ActionUpdate) @@ -395,90 +389,41 @@ func (r *ComponentReconciler) ensureRobotAccountSecret(ctx context.Context, comp return secretData, nil } -// ensureComponentPullSecretRemoteSecret creates remote secret for component image repository pull token. -func (r *ComponentReconciler) ensureComponentPullSecretRemoteSecret(ctx context.Context, component *appstudioredhatcomv1alpha1.Component, remoteSecretName string) error { +// ensureComponentPullSecret creates secret for component image repository pull token. +func (r *ComponentReconciler) ensureComponentPullSecret(ctx context.Context, component *appstudioredhatcomv1alpha1.Component, secretName string, robotAccount *quay.RobotAccount, imageURL string) error { log := ctrllog.FromContext(ctx) - remoteSecret := &remotesecretv1beta1.RemoteSecret{} - remoteSecretKey := types.NamespacedName{Namespace: component.Namespace, Name: remoteSecretName} - if err := r.Client.Get(ctx, remoteSecretKey, remoteSecret); err != nil { + pullSecret := &corev1.Secret{} + pullSecretKey := types.NamespacedName{Namespace: component.Namespace, Name: secretName} + if err := r.Client.Get(ctx, pullSecretKey, pullSecret); err != nil { if !errors.IsNotFound(err) { - log.Error(err, fmt.Sprintf("failed to get remote secret: %v", remoteSecretKey), l.Action, l.ActionView) + log.Error(err, fmt.Sprintf("failed to get pull secret: %v", pullSecretKey), l.Action, l.ActionView) return err } - remoteSecret := &remotesecretv1beta1.RemoteSecret{ + pullSecret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: remoteSecretName, + Name: secretName, Namespace: component.Namespace, - // TODO: remove application/component labels when SEB controller will be discontinued Labels: map[string]string{ - ApplicationNameLabelName: component.Spec.Application, - ComponentNameLabelName: component.Name, - InternalRemoteSecretLabelName: "true", - }, - OwnerReferences: []metav1.OwnerReference{ - { - Name: component.Name, - APIVersion: component.APIVersion, - Kind: component.Kind, - UID: component.UID, - }, - }, - }, - Spec: remotesecretv1beta1.RemoteSecretSpec{ - Secret: remotesecretv1beta1.LinkableSecretSpec{ - Name: remoteSecretName, - Type: corev1.SecretTypeDockerConfigJson, - LinkedTo: []remotesecretv1beta1.SecretLink{ - { - ServiceAccount: remotesecretv1beta1.ServiceAccountLink{ - Reference: corev1.LocalObjectReference{ - Name: defaultServiceAccountName, - }, - }, - }, - }, - }, - Targets: []remotesecretv1beta1.RemoteSecretTarget{ - { - Namespace: component.Namespace, - }, + InternalSecretLabelName: "true", }, }, + Type: corev1.SecretTypeDockerConfigJson, + StringData: generateDockerconfigSecretData(imageURL, robotAccount), } - if err := r.Client.Create(ctx, remoteSecret); err != nil { - log.Error(err, fmt.Sprintf("failed to create remote secret: %v", remoteSecretKey), l.Action, l.ActionAdd, l.Audit, "true") + + if err := controllerutil.SetOwnerReference(component, pullSecret, r.Scheme); err != nil { + log.Error(err, "failed to set owner for pull secret") return err } - } - - return nil -} -// createRemoteSecretUploadSecret creates short lived secret to upload data into specified remote secret. -func (r *ComponentReconciler) createRemoteSecretUploadSecret(ctx context.Context, robotAccount *quay.RobotAccount, namespace, remoteSecretName, imageURL string) error { - log := ctrllog.FromContext(ctx) + if err := r.Client.Create(ctx, pullSecret); err != nil { + log.Error(err, fmt.Sprintf("failed to create pull secret: %v", pullSecretKey), l.Action, l.ActionAdd, l.Audit, "true") + return err + } - uploadSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "upload-secret-" + remoteSecretName, - Namespace: namespace, - Labels: map[string]string{ - remotesecretv1beta1.UploadSecretLabel: "remotesecret", - }, - Annotations: map[string]string{ - remotesecretv1beta1.RemoteSecretNameAnnotation: remoteSecretName, - }, - }, - Type: corev1.SecretTypeDockerConfigJson, - StringData: generateDockerconfigSecretData(imageURL, robotAccount), } - if err := r.Client.Create(ctx, uploadSecret); err != nil { - log.Error(err, fmt.Sprintf("failed to create upload secret: %v", uploadSecret.Name), l.Action, l.ActionAdd, l.Audit, "true") - return err - } - return nil } diff --git a/controllers/component_image_controller_test.go b/controllers/component_image_controller_test.go index 34e1b9b..ee2a1b9 100644 --- a/controllers/component_image_controller_test.go +++ b/controllers/component_image_controller_test.go @@ -26,9 +26,7 @@ import ( . "github.com/onsi/gomega" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - remotesecretv1beta1 "github.com/redhat-appstudio/remote-secret/api/v1beta1" corev1 "k8s.io/api/core/v1" - k8sErrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "github.com/konflux-ci/image-controller/pkg/quay" @@ -46,7 +44,7 @@ var _ = Describe("Component image controller", func() { pullToken string expectedPushRobotAccountName string expectedPullRobotAccountName string - expectedRemoteSecretName string + expectedPullSecretName string expectedRepoName string expectedImage string ) @@ -62,7 +60,7 @@ var _ = Describe("Component image controller", func() { pullToken = "pull-token1234" expectedPushRobotAccountName = fmt.Sprintf("%s%s%s", defaultNamespace, defaultComponentApplication, defaultComponentName) expectedPullRobotAccountName = expectedPushRobotAccountName + "-pull" - expectedRemoteSecretName = resourceKey.Name + "-pull" + expectedPullSecretName = resourceKey.Name + "-pull" expectedRepoName = fmt.Sprintf("%s/%s/%s", defaultNamespace, defaultComponentApplication, defaultComponentName) expectedImage = fmt.Sprintf("quay.io/%s/%s", quay.TestQuayOrg, expectedRepoName) }) @@ -158,31 +156,17 @@ var _ = Describe("Component image controller", func() { It("should propagate pull secret to environments", func() { component := getComponent(resourceKey) - remoteSecretKey := types.NamespacedName{Name: expectedRemoteSecretName, Namespace: defaultNamespace} - remoteSecret := waitRemoteSecretExist(remoteSecretKey) - Expect(remoteSecret.Labels[ApplicationNameLabelName]).To(Equal(component.Spec.Application)) - Expect(remoteSecret.Labels[ComponentNameLabelName]).To(Equal(component.Spec.ComponentName)) - Expect(remoteSecret.Labels[InternalRemoteSecretLabelName]).To(Equal("true")) - Expect(remoteSecret.OwnerReferences).To(HaveLen(1)) - Expect(remoteSecret.OwnerReferences[0].Name).To(Equal(component.Name)) - Expect(remoteSecret.OwnerReferences[0].Kind).To(Equal("Component")) - - Expect(remoteSecret.Spec.Secret.Name).To(Equal(remoteSecretKey.Name)) - Expect(remoteSecret.Spec.Secret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - Expect(remoteSecret.Spec.Secret.LinkedTo).To(HaveLen(1)) - Expect(remoteSecret.Spec.Secret.LinkedTo[0].ServiceAccount.Reference.Name).To(Equal(defaultServiceAccountName)) - Expect(remoteSecret.Spec.Targets).To(HaveLen(1)) - Expect(remoteSecret.Spec.Targets[0].Namespace).To(Equal(component.Namespace)) - - waitSecretExist(uploadSecretKey) - uploadSecret := &corev1.Secret{} - Expect(k8sClient.Get(ctx, uploadSecretKey, uploadSecret)).To(Succeed()) - - Expect(uploadSecret.Labels[remotesecretv1beta1.UploadSecretLabel]).To(Equal("remotesecret")) - Expect(uploadSecret.Annotations[remotesecretv1beta1.RemoteSecretNameAnnotation]).To(Equal(remoteSecretKey.Name)) - Expect(uploadSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - - uploadSecretDockerconfigJson := string(uploadSecret.Data[corev1.DockerConfigJsonKey]) + pullSecretKey := types.NamespacedName{Name: expectedPullSecretName, Namespace: defaultNamespace} + pullSecret := waitSecretExist(pullSecretKey) + Expect(pullSecret.Labels[InternalSecretLabelName]).To(Equal("true")) + Expect(pullSecret.OwnerReferences).To(HaveLen(1)) + Expect(pullSecret.OwnerReferences[0].Name).To(Equal(component.Name)) + Expect(pullSecret.OwnerReferences[0].Kind).To(Equal("Component")) + + Expect(pullSecret.Name).To(Equal(pullSecretKey.Name)) + Expect(pullSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) + + uploadSecretDockerconfigJson := string(pullSecret.Data[corev1.DockerConfigJsonKey]) var authDataJson interface{} Expect(json.Unmarshal([]byte(uploadSecretDockerconfigJson), &authDataJson)).To(Succeed()) Expect(uploadSecretDockerconfigJson).To(ContainSubstring(expectedImage)) @@ -603,10 +587,9 @@ var _ = Describe("Component image controller", func() { }) It("should create pull robot account for existing image repositories with only push robot account and propagate it via remote secret", func() { - deleteSecret(types.NamespacedName{Name: expectedRemoteSecretName, Namespace: resourceKey.Namespace}) + deleteSecret(types.NamespacedName{Name: expectedPullSecretName, Namespace: resourceKey.Namespace}) - remoteSecretKey := types.NamespacedName{Name: expectedRemoteSecretName, Namespace: defaultNamespace} - Expect(k8sErrors.IsNotFound(k8sClient.Get(ctx, remoteSecretKey, &remotesecretv1beta1.RemoteSecret{}))) + pullSecretKey := types.NamespacedName{Name: expectedPullSecretName, Namespace: defaultNamespace} isCreateRepositoryInvoked := false quay.CreateRepositoryFunc = func(repository quay.RepositoryRequest) (*quay.Repository, error) { @@ -682,21 +665,15 @@ var _ = Describe("Component image controller", func() { Expect(repoImageInfo.Visibility).To(Equal("public")) Expect(repoImageInfo.Secret).To(Equal(resourceKey.Name)) - remoteSecret := waitRemoteSecretExist(remoteSecretKey) - Expect(remoteSecret.Labels[ApplicationNameLabelName]).To(Equal(component.Spec.Application)) - Expect(remoteSecret.Labels[ComponentNameLabelName]).To(Equal(component.Spec.ComponentName)) - Expect(remoteSecret.Labels[InternalRemoteSecretLabelName]).To(Equal("true")) - Expect(remoteSecret.OwnerReferences).To(HaveLen(1)) - Expect(remoteSecret.OwnerReferences[0].Name).To(Equal(component.Name)) - Expect(remoteSecret.OwnerReferences[0].Kind).To(Equal("Component")) - - Expect(remoteSecret.Spec.Secret.Name).To(Equal(remoteSecretKey.Name)) - Expect(remoteSecret.Spec.Secret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - Expect(remoteSecret.Spec.Secret.LinkedTo).To(HaveLen(1)) - Expect(remoteSecret.Spec.Secret.LinkedTo[0].ServiceAccount.Reference.Name).To(Equal(defaultServiceAccountName)) - Expect(remoteSecret.Spec.Targets).To(HaveLen(1)) - Expect(remoteSecret.Spec.Targets[0].Namespace).To(Equal(component.Namespace)) + pullSecret := waitSecretExist(pullSecretKey) + Expect(pullSecret.Labels[InternalSecretLabelName]).To(Equal("true")) + Expect(pullSecret.OwnerReferences).To(HaveLen(1)) + Expect(pullSecret.OwnerReferences[0].Name).To(Equal(component.Name)) + Expect(pullSecret.OwnerReferences[0].Kind).To(Equal("Component")) + Expect(pullSecret.Name).To(Equal(pullSecretKey.Name)) + Expect(pullSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) + Expect(pullSecret.Data).To(HaveKey(".dockerconfigjson")) }) }) diff --git a/controllers/imagerepository_controller.go b/controllers/imagerepository_controller.go index 60576eb..ea04319 100644 --- a/controllers/imagerepository_controller.go +++ b/controllers/imagerepository_controller.go @@ -30,7 +30,6 @@ import ( "github.com/konflux-ci/image-controller/pkg/metrics" "github.com/konflux-ci/image-controller/pkg/quay" appstudioredhatcomv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" - remotesecretv1beta1 "github.com/redhat-appstudio/remote-secret/api/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,7 +42,7 @@ import ( ) const ( - InternalRemoteSecretLabelName = "appstudio.redhat.com/internal" + InternalSecretLabelName = "appstudio.redhat.com/internal" ImageRepositoryFinalizer = "appstudio.openshift.io/image-repository" @@ -375,11 +374,9 @@ func (r *ImageRepositoryReconciler) ProvisionImageRepository(ctx context.Context status.Image.Visibility = imageRepository.Spec.Image.Visibility status.Credentials.GenerationTimestamp = &metav1.Time{Time: time.Now()} status.Credentials.PushRobotAccountName = pushCredentialsInfo.RobotAccountName - status.Credentials.PushRemoteSecretName = pushCredentialsInfo.RemoteSecretName status.Credentials.PushSecretName = pushCredentialsInfo.SecretName if isComponentLinked(imageRepository) { status.Credentials.PullRobotAccountName = pullCredentialsInfo.RobotAccountName - status.Credentials.PullRemoteSecretName = pullCredentialsInfo.RemoteSecretName status.Credentials.PullSecretName = pullCredentialsInfo.SecretName } status.Notifications = notificationStatus @@ -411,7 +408,6 @@ func (r *ImageRepositoryReconciler) ProvisionImageRepository(ctx context.Context type imageRepositoryAccessData struct { RobotAccountName string - RemoteSecretName string SecretName string } @@ -442,19 +438,14 @@ func (r *ImageRepositoryReconciler) ProvisionImageRepositoryAccess(ctx context.C return nil, err } - remoteSecretName := getRemoteSecretName(imageRepository, isPullOnly) - if err := r.EnsureRemoteSecret(ctx, imageRepository, remoteSecretName, isPullOnly); err != nil { - return nil, err - } - - if err := r.CreateRemoteSecretUploadSecret(ctx, robotAccount, imageRepository.Namespace, remoteSecretName, quayImageURL); err != nil { + secretName := getSecretName(imageRepository, isPullOnly) + if err := r.EnsureSecret(ctx, imageRepository, secretName, robotAccount, quayImageURL, isPullOnly); err != nil { return nil, err } data := &imageRepositoryAccessData{ RobotAccountName: robotAccountName, - RemoteSecretName: remoteSecretName, - SecretName: remoteSecretName, + SecretName: secretName, } return data, nil } @@ -507,17 +498,13 @@ func (r *ImageRepositoryReconciler) RegenerateImageRepositoryAccessToken(ctx con log.Info("Refreshed quay robot account token") } - remoteSecretName := imageRepository.Status.Credentials.PushRemoteSecretName + secretName := imageRepository.Status.Credentials.PushSecretName if isPullOnly { - remoteSecretName = imageRepository.Status.Credentials.PullRemoteSecretName + secretName = imageRepository.Status.Credentials.PullSecretName } - if err := r.EnsureRemoteSecret(ctx, imageRepository, remoteSecretName, isPullOnly); err != nil { + if err := r.EnsureSecret(ctx, imageRepository, secretName, robotAccount, quayImageURL, isPullOnly); err != nil { return err } - if err := r.CreateRemoteSecretUploadSecret(ctx, robotAccount, imageRepository.Namespace, remoteSecretName, quayImageURL); err != nil { - return err - } - return nil } @@ -599,100 +586,55 @@ func (r *ImageRepositoryReconciler) ChangeImageRepositoryVisibility(ctx context. return err } -func (r *ImageRepositoryReconciler) EnsureRemoteSecret(ctx context.Context, imageRepository *imagerepositoryv1alpha1.ImageRepository, remoteSecretName string, isPull bool) error { - log := ctrllog.FromContext(ctx).WithValues("RemoteSecretName", remoteSecretName) +func (r *ImageRepositoryReconciler) EnsureSecret(ctx context.Context, imageRepository *imagerepositoryv1alpha1.ImageRepository, secretName string, robotAccount *quay.RobotAccount, imageURL string, isPull bool) error { + log := ctrllog.FromContext(ctx).WithValues("SecretName", secretName) - remoteSecret := &remotesecretv1beta1.RemoteSecret{} - remoteSecretKey := types.NamespacedName{Namespace: imageRepository.Namespace, Name: remoteSecretName} - if err := r.Client.Get(ctx, remoteSecretKey, remoteSecret); err != nil { + secret := &corev1.Secret{} + secretKey := types.NamespacedName{Namespace: imageRepository.Namespace, Name: secretName} + if err := r.Client.Get(ctx, secretKey, secret); err != nil { if !errors.IsNotFound(err) { log.Error(err, "failed to get remote secret", l.Action, l.ActionView) return err } - serviceAccountName := buildPipelineServiceAccountName - if isPull { - serviceAccountName = defaultServiceAccountName - } - - remoteSecret := &remotesecretv1beta1.RemoteSecret{ + secret = &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: remoteSecretName, + Name: secretName, Namespace: imageRepository.Namespace, Labels: map[string]string{ - InternalRemoteSecretLabelName: "true", - }, - }, - Spec: remotesecretv1beta1.RemoteSecretSpec{ - Secret: remotesecretv1beta1.LinkableSecretSpec{ - Name: remoteSecretName, - Type: corev1.SecretTypeDockerConfigJson, - LinkedTo: []remotesecretv1beta1.SecretLink{ - { - ServiceAccount: remotesecretv1beta1.ServiceAccountLink{ - Reference: corev1.LocalObjectReference{ - Name: serviceAccountName, - }, - }, - }, - }, - }, - Targets: []remotesecretv1beta1.RemoteSecretTarget{ - { - Namespace: imageRepository.Namespace, - }, + InternalSecretLabelName: "true", }, }, + Type: corev1.SecretTypeDockerConfigJson, + StringData: generateDockerconfigSecretData(imageURL, robotAccount), } - // TODO: remove application/component labels when SEB controller will be discontinued - if isPull { - remoteSecret.Labels[ApplicationNameLabelName] = imageRepository.Labels[ApplicationNameLabelName] - remoteSecret.Labels[ComponentNameLabelName] = imageRepository.Labels[ComponentNameLabelName] - } - - if err := controllerutil.SetOwnerReference(imageRepository, remoteSecret, r.Scheme); err != nil { - log.Error(err, "failed to set owner for remote secret") + if err := controllerutil.SetOwnerReference(imageRepository, secret, r.Scheme); err != nil { + log.Error(err, "failed to set owner for image repository secret") return err } - if err := r.Client.Create(ctx, remoteSecret); err != nil { - log.Error(err, "failed to create remote secret", l.Action, l.ActionAdd, l.Audit, "true") + if err := r.Client.Create(ctx, secret); err != nil { + log.Error(err, "failed to create image repository secret", l.Action, l.ActionAdd, l.Audit, "true") return err } else { - log.Info("Remote Secret created") + log.Info("Image repository secret created") } - } - - return nil -} -// CreateRemoteSecretUploadSecret propagates credentials from given robot account to corresponding remote secret. -func (r *ImageRepositoryReconciler) CreateRemoteSecretUploadSecret(ctx context.Context, robotAccount *quay.RobotAccount, namespace, remoteSecretName, imageURL string) error { - uploadSecretName := "upload-secret-" + remoteSecretName - log := ctrllog.FromContext(ctx).WithValues("RemoteSecretName", remoteSecretName).WithValues("UploadSecretName", uploadSecretName) - - uploadSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: uploadSecretName, - Namespace: namespace, - Labels: map[string]string{ - remotesecretv1beta1.UploadSecretLabel: "remotesecret", - }, - Annotations: map[string]string{ - remotesecretv1beta1.RemoteSecretNameAnnotation: remoteSecretName, - }, - }, - Type: corev1.SecretTypeDockerConfigJson, - StringData: generateDockerconfigSecretData(imageURL, robotAccount), - } - if err := r.Client.Create(ctx, uploadSecret); err != nil { - log.Error(err, "failed to create upload secret", l.Action, l.ActionAdd, l.Audit, "true") - return err - } else { - log.Info("Created upload Secret for Remote Secret") + if !isPull { + serviceAccount := &corev1.ServiceAccount{} + serviceAccountKey := types.NamespacedName{Namespace: imageRepository.Namespace, Name: buildPipelineServiceAccountName} + if err := r.Client.Get(ctx, serviceAccountKey, serviceAccount); err != nil { + log.Error(err, "failed to get service account", l.Action, l.ActionView) + return err + } + serviceAccount.Secrets = append(serviceAccount.Secrets, corev1.ObjectReference{Name: secretName}) + if err := r.Client.Update(ctx, serviceAccount); err != nil { + log.Error(err, "failed to update service account", l.Action, l.ActionUpdate) + return err + } + } } - return nil } @@ -717,17 +659,17 @@ func generateQuayRobotAccountName(imageRepositoryName string, isPullOnly bool) s return robotAccountName } -func getRemoteSecretName(imageRepository *imagerepositoryv1alpha1.ImageRepository, isPullOnly bool) string { - remoteSecretName := imageRepository.Name - if len(remoteSecretName) > 220 { - remoteSecretName = remoteSecretName[:220] +func getSecretName(imageRepository *imagerepositoryv1alpha1.ImageRepository, isPullOnly bool) string { + secretName := imageRepository.Name + if len(secretName) > 220 { + secretName = secretName[:220] } if isPullOnly { - remoteSecretName += "-image-pull" + secretName += "-image-pull" } else { - remoteSecretName += "-image-push" + secretName += "-image-push" } - return remoteSecretName + return secretName } func isComponentLinked(imageRepository *imagerepositoryv1alpha1.ImageRepository) bool { diff --git a/controllers/imagerepository_controller_test.go b/controllers/imagerepository_controller_test.go index 8e75bcb..cfd8995 100644 --- a/controllers/imagerepository_controller_test.go +++ b/controllers/imagerepository_controller_test.go @@ -26,8 +26,6 @@ import ( "github.com/konflux-ci/image-controller/pkg/quay" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - remotesecretv1beta1 "github.com/redhat-appstudio/remote-secret/api/v1beta1" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -52,7 +50,6 @@ var _ = Describe("Image repository controller", func() { BeforeEach(func() { quay.ResetTestQuayClientToFails() - deleteUploadSecrets(defaultNamespace) }) It("should prepare environment", func() { @@ -62,6 +59,7 @@ var _ = Describe("Image repository controller", func() { expectedImageName = fmt.Sprintf("%s/%s", defaultNamespace, defaultImageRepositoryName) expectedImage = fmt.Sprintf("quay.io/%s/%s", quay.TestQuayOrg, expectedImageName) expectedRobotAccountPrefix = strings.ReplaceAll(strings.ReplaceAll(expectedImageName, "-", "_"), "/", "_") + createServiceAccount(defaultNamespace, buildPipelineServiceAccountName) }) It("should provision image repository", func() { @@ -103,9 +101,6 @@ var _ = Describe("Image repository controller", func() { createImageRepository(imageRepositoryConfig{}) - uploadSecretKey := types.NamespacedName{Name: "upload-secret-" + resourceKey.Name + "-image-push", Namespace: resourceKey.Namespace} - defer deleteSecret(uploadSecretKey) - Eventually(func() bool { return isCreateRepositoryInvoked }, timeout, interval).Should(BeTrue()) Eventually(func() bool { return isCreateRobotAccountInvoked }, timeout, interval).Should(BeTrue()) Eventually(func() bool { return isAddPushPermissionsToRobotAccountInvoked }, timeout, interval).Should(BeTrue()) @@ -122,43 +117,36 @@ var _ = Describe("Image repository controller", func() { Expect(imageRepository.Status.Image.URL).To(Equal(expectedImage)) Expect(imageRepository.Status.Image.Visibility).To(Equal(imagerepositoryv1alpha1.ImageVisibilityPublic)) Expect(imageRepository.Status.Credentials.PushRobotAccountName).To(HavePrefix(expectedRobotAccountPrefix)) - Expect(imageRepository.Status.Credentials.PushRemoteSecretName).To(Equal(imageRepository.Name + "-image-push")) Expect(imageRepository.Status.Credentials.PushSecretName).To(Equal(imageRepository.Name + "-image-push")) Expect(imageRepository.Status.Credentials.GenerationTimestamp).ToNot(BeNil()) Expect(imageRepository.Status.Notifications).To(HaveLen(0)) - remoteSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PushRemoteSecretName, Namespace: imageRepository.Namespace} - remoteSecret := waitRemoteSecretExist(remoteSecretKey) - Expect(remoteSecret.OwnerReferences).To(HaveLen(1)) - Expect(remoteSecret.OwnerReferences[0].Kind).To(Equal("ImageRepository")) - Expect(remoteSecret.OwnerReferences[0].Name).To(Equal(imageRepository.GetName())) - Expect(remoteSecret.Labels[InternalRemoteSecretLabelName]).To(Equal("true")) - Expect(remoteSecret.Spec.Secret.Name).To(Equal(remoteSecret.Name)) - Expect(remoteSecret.Spec.Secret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - Expect(remoteSecret.Spec.Secret.LinkedTo).To(HaveLen(1)) - Expect(remoteSecret.Spec.Secret.LinkedTo[0].ServiceAccount.Reference.Name).To(Equal(buildPipelineServiceAccountName)) - Expect(remoteSecret.Spec.Targets).To(HaveLen(1)) - Expect(remoteSecret.Spec.Targets[0].Namespace).To(Equal(imageRepository.Namespace)) - - uploadSecret := waitSecretExist(uploadSecretKey) - Expect(uploadSecret.Labels[remotesecretv1beta1.UploadSecretLabel]).To(Equal("remotesecret")) - Expect(uploadSecret.Annotations[remotesecretv1beta1.RemoteSecretNameAnnotation]).To(Equal(remoteSecret.Name)) - Expect(uploadSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - uploadSecretDockerconfigJson := string(uploadSecret.Data[corev1.DockerConfigJsonKey]) + pushSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PushSecretName, Namespace: imageRepository.Namespace} + pushSecret := waitSecretExist(pushSecretKey) + defer deleteSecret(pushSecretKey) + Expect(pushSecret.OwnerReferences).To(HaveLen(1)) + Expect(pushSecret.OwnerReferences[0].Kind).To(Equal("ImageRepository")) + Expect(pushSecret.OwnerReferences[0].Name).To(Equal(imageRepository.GetName())) + Expect(pushSecret.Labels[InternalSecretLabelName]).To(Equal("true")) + Expect(pushSecret.Name).To(Equal(pushSecret.Name)) + Expect(pushSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) + + sa := getServiceAccount(defaultNamespace, buildPipelineServiceAccountName) + Expect(sa.Secrets).To(ContainElement(corev1.ObjectReference{Name: pushSecret.Name})) + + pushSecretDockerconfigJson := string(pushSecret.Data[corev1.DockerConfigJsonKey]) var authDataJson interface{} - Expect(json.Unmarshal([]byte(uploadSecretDockerconfigJson), &authDataJson)).To(Succeed()) - Expect(uploadSecretDockerconfigJson).To(ContainSubstring(expectedImage)) - uploadSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(uploadSecretDockerconfigJson)[1]) + Expect(json.Unmarshal([]byte(pushSecretDockerconfigJson), &authDataJson)).To(Succeed()) + Expect(pushSecretDockerconfigJson).To(ContainSubstring(expectedImage)) + pushSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pushSecretDockerconfigJson)[1]) Expect(err).To(Succeed()) pushRobotAccountName := imageRepository.Status.Credentials.PushRobotAccountName - Expect(string(uploadSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pushRobotAccountName, pushToken))) + Expect(string(pushSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pushRobotAccountName, pushToken))) }) It("should regenerate token", func() { newToken := "push-token5678" - uploadSecretKey := types.NamespacedName{Name: "upload-secret-" + resourceKey.Name + "-image-push", Namespace: resourceKey.Namespace} - // Wait just for case it takes less than a second to regenerate credentials time.Sleep(time.Second) @@ -176,7 +164,6 @@ var _ = Describe("Image repository controller", func() { regenerateToken := true imageRepository.Spec.Credentials = &imagerepositoryv1alpha1.ImageCredentials{RegenerateToken: ®enerateToken} Expect(k8sClient.Update(ctx, imageRepository)).To(Succeed()) - defer deleteSecret(uploadSecretKey) Eventually(func() bool { return isRegenerateRobotAccountTokenInvoked }, timeout, interval).Should(BeTrue()) Eventually(func() bool { @@ -186,21 +173,19 @@ var _ = Describe("Image repository controller", func() { *imageRepository.Status.Credentials.GenerationTimestamp != oldTokenGenerationTimestamp }, timeout, interval).Should(BeTrue()) - remoteSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PushRemoteSecretName, Namespace: imageRepository.Namespace} - remoteSecret := waitRemoteSecretExist(remoteSecretKey) + pushSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PushSecretName, Namespace: imageRepository.Namespace} + pushSecret := waitSecretExist(pushSecretKey) + defer deleteSecret(pushSecretKey) - uploadSecret := waitSecretExist(uploadSecretKey) - Expect(uploadSecret.Labels[remotesecretv1beta1.UploadSecretLabel]).To(Equal("remotesecret")) - Expect(uploadSecret.Annotations[remotesecretv1beta1.RemoteSecretNameAnnotation]).To(Equal(remoteSecret.Name)) - Expect(uploadSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - uploadSecretDockerconfigJson := string(uploadSecret.Data[corev1.DockerConfigJsonKey]) + Expect(pushSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) + pushSecretDockerconfigJson := string(pushSecret.Data[corev1.DockerConfigJsonKey]) var authDataJson interface{} - Expect(json.Unmarshal([]byte(uploadSecretDockerconfigJson), &authDataJson)).To(Succeed()) - Expect(uploadSecretDockerconfigJson).To(ContainSubstring(expectedImage)) - uploadSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(uploadSecretDockerconfigJson)[1]) + Expect(json.Unmarshal([]byte(pushSecretDockerconfigJson), &authDataJson)).To(Succeed()) + Expect(pushSecretDockerconfigJson).To(ContainSubstring(expectedImage)) + pushSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pushSecretDockerconfigJson)[1]) Expect(err).To(Succeed()) pushRobotAccountName := imageRepository.Status.Credentials.PushRobotAccountName - Expect(string(uploadSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pushRobotAccountName, newToken))) + Expect(string(pushSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pushRobotAccountName, newToken))) }) It("should update image visibility", func() { @@ -268,7 +253,6 @@ var _ = Describe("Image repository controller", func() { BeforeEach(func() { quay.ResetTestQuayClientToFails() - deleteUploadSecrets(defaultNamespace) createComponent(componentConfig{}) }) @@ -355,11 +339,6 @@ var _ = Describe("Image repository controller", func() { createImageRepository(imageRepositoryConfigObject) - pushUploadSecretKey := types.NamespacedName{Name: "upload-secret-" + resourceKey.Name + "-image-push", Namespace: resourceKey.Namespace} - pullUploadSecretKey := types.NamespacedName{Name: "upload-secret-" + resourceKey.Name + "-image-pull", Namespace: resourceKey.Namespace} - defer deleteSecret(pushUploadSecretKey) - defer deleteSecret(pullUploadSecretKey) - Eventually(func() bool { return isCreateRepositoryInvoked }, timeout, interval).Should(BeTrue()) Eventually(func() bool { return isCreatePushRobotAccountInvoked }, timeout, interval).Should(BeTrue()) Eventually(func() bool { return isCreatePullRobotAccountInvoked }, timeout, interval).Should(BeTrue()) @@ -390,70 +369,53 @@ var _ = Describe("Image repository controller", func() { Expect(imageRepository.Status.Image.URL).To(Equal(expectedImage)) Expect(imageRepository.Status.Image.Visibility).To(Equal(imagerepositoryv1alpha1.ImageVisibilityPublic)) Expect(imageRepository.Status.Credentials.PushRobotAccountName).To(HavePrefix(expectedRobotAccountPrefix)) - Expect(imageRepository.Status.Credentials.PushRemoteSecretName).To(Equal(imageRepository.Name + "-image-push")) Expect(imageRepository.Status.Credentials.PushSecretName).To(Equal(imageRepository.Name + "-image-push")) Expect(imageRepository.Status.Credentials.PullRobotAccountName).To(HavePrefix(expectedRobotAccountPrefix)) Expect(imageRepository.Status.Credentials.PullRobotAccountName).To(HaveSuffix("_pull")) - Expect(imageRepository.Status.Credentials.PullRemoteSecretName).To(Equal(imageRepository.Name + "-image-pull")) Expect(imageRepository.Status.Credentials.PullSecretName).To(Equal(imageRepository.Name + "-image-pull")) Expect(imageRepository.Status.Credentials.GenerationTimestamp).ToNot(BeNil()) Expect(imageRepository.Status.Notifications).To(HaveLen(1)) Expect(imageRepository.Status.Notifications[0].UUID).To(Equal("uuid")) Expect(imageRepository.Status.Notifications[0].Title).To(Equal("test-notification")) - pushRemoteSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PushRemoteSecretName, Namespace: imageRepository.Namespace} - pushRemoteSecret := waitRemoteSecretExist(pushRemoteSecretKey) - Expect(pushRemoteSecret.Labels[InternalRemoteSecretLabelName]).To(Equal("true")) - Expect(pushRemoteSecret.OwnerReferences).To(HaveLen(1)) - Expect(pushRemoteSecret.OwnerReferences[0].Kind).To(Equal("ImageRepository")) - Expect(pushRemoteSecret.OwnerReferences[0].Name).To(Equal(imageRepository.GetName())) - Expect(pushRemoteSecret.Spec.Secret.Name).To(Equal(pushRemoteSecret.Name)) - Expect(pushRemoteSecret.Spec.Secret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - Expect(pushRemoteSecret.Spec.Secret.LinkedTo).To(HaveLen(1)) - Expect(pushRemoteSecret.Spec.Secret.LinkedTo[0].ServiceAccount.Reference.Name).To(Equal(buildPipelineServiceAccountName)) - Expect(pushRemoteSecret.Spec.Targets).To(HaveLen(1)) - Expect(pushRemoteSecret.Spec.Targets[0].Namespace).To(Equal(imageRepository.Namespace)) - - pullRemoteSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PullRemoteSecretName, Namespace: imageRepository.Namespace} - pullRemoteSecret := waitRemoteSecretExist(pullRemoteSecretKey) - Expect(pullRemoteSecret.Labels[ApplicationNameLabelName]).To(Equal(defaultComponentApplication)) - Expect(pullRemoteSecret.Labels[ComponentNameLabelName]).To(Equal(defaultComponentName)) - Expect(pullRemoteSecret.Labels[InternalRemoteSecretLabelName]).To(Equal("true")) - Expect(pullRemoteSecret.OwnerReferences).To(HaveLen(1)) - Expect(pullRemoteSecret.OwnerReferences[0].Name).To(Equal(imageRepository.Name)) - Expect(pullRemoteSecret.OwnerReferences[0].Kind).To(Equal("ImageRepository")) - Expect(pullRemoteSecret.Spec.Secret.Name).To(Equal(pullRemoteSecretKey.Name)) - Expect(pullRemoteSecret.Spec.Secret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - Expect(pullRemoteSecret.Spec.Secret.LinkedTo).To(HaveLen(1)) - Expect(pullRemoteSecret.Spec.Secret.LinkedTo[0].ServiceAccount.Reference.Name).To(Equal(defaultServiceAccountName)) - Expect(pullRemoteSecret.Spec.Targets).To(HaveLen(1)) - Expect(pullRemoteSecret.Spec.Targets[0].Namespace).To(Equal(imageRepository.Namespace)) + pushSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PushSecretName, Namespace: imageRepository.Namespace} + pushSecret := waitSecretExist(pushSecretKey) + defer deleteSecret(pushSecretKey) + Expect(pushSecret.Labels[InternalSecretLabelName]).To(Equal("true")) + Expect(pushSecret.OwnerReferences).To(HaveLen(1)) + Expect(pushSecret.OwnerReferences[0].Kind).To(Equal("ImageRepository")) + Expect(pushSecret.OwnerReferences[0].Name).To(Equal(imageRepository.GetName())) + Expect(pushSecret.Name).To(Equal(pushSecret.Name)) + Expect(pushSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) + + pullSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PullSecretName, Namespace: imageRepository.Namespace} + pullSecret := waitSecretExist(pullSecretKey) + defer deleteSecret(pullSecretKey) + + Expect(pullSecret.Labels[InternalSecretLabelName]).To(Equal("true")) + Expect(pullSecret.OwnerReferences).To(HaveLen(1)) + Expect(pullSecret.OwnerReferences[0].Name).To(Equal(imageRepository.Name)) + Expect(pullSecret.OwnerReferences[0].Kind).To(Equal("ImageRepository")) + Expect(pullSecret.Name).To(Equal(pullSecretKey.Name)) + Expect(pullSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) var authDataJson interface{} - pushUploadSecret := waitSecretExist(pushUploadSecretKey) - Expect(pushUploadSecret.Labels[remotesecretv1beta1.UploadSecretLabel]).To(Equal("remotesecret")) - Expect(pushUploadSecret.Annotations[remotesecretv1beta1.RemoteSecretNameAnnotation]).To(Equal(pushRemoteSecret.Name)) - Expect(pushUploadSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - pushUploadSecretDockerconfigJson := string(pushUploadSecret.Data[corev1.DockerConfigJsonKey]) - Expect(json.Unmarshal([]byte(pushUploadSecretDockerconfigJson), &authDataJson)).To(Succeed()) - Expect(pushUploadSecretDockerconfigJson).To(ContainSubstring(expectedImage)) - pushUploadSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pushUploadSecretDockerconfigJson)[1]) + pushSecretDockerconfigJson := string(pushSecret.Data[corev1.DockerConfigJsonKey]) + Expect(json.Unmarshal([]byte(pushSecretDockerconfigJson), &authDataJson)).To(Succeed()) + Expect(pushSecretDockerconfigJson).To(ContainSubstring(expectedImage)) + pushSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pushSecretDockerconfigJson)[1]) Expect(err).To(Succeed()) pushRobotAccountName := imageRepository.Status.Credentials.PushRobotAccountName - Expect(string(pushUploadSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pushRobotAccountName, pushToken))) - - pullUploadSecret := waitSecretExist(pullUploadSecretKey) - Expect(pullUploadSecret.Labels[remotesecretv1beta1.UploadSecretLabel]).To(Equal("remotesecret")) - Expect(pullUploadSecret.Annotations[remotesecretv1beta1.RemoteSecretNameAnnotation]).To(Equal(pullRemoteSecret.Name)) - Expect(pullUploadSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - pullUploadSecretDockerconfigJson := string(pullUploadSecret.Data[corev1.DockerConfigJsonKey]) - Expect(json.Unmarshal([]byte(pullUploadSecretDockerconfigJson), &authDataJson)).To(Succeed()) - Expect(pullUploadSecretDockerconfigJson).To(ContainSubstring(expectedImage)) - pullUploadSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pullUploadSecretDockerconfigJson)[1]) + Expect(string(pushSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pushRobotAccountName, pushToken))) + + pullSecretDockerconfigJson := string(pullSecret.Data[corev1.DockerConfigJsonKey]) + Expect(json.Unmarshal([]byte(pullSecretDockerconfigJson), &authDataJson)).To(Succeed()) + Expect(pullSecretDockerconfigJson).To(ContainSubstring(expectedImage)) + pullSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pullSecretDockerconfigJson)[1]) Expect(err).To(Succeed()) pullRobotAccountName := imageRepository.Status.Credentials.PullRobotAccountName - Expect(string(pullUploadSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pullRobotAccountName, pullToken))) + Expect(string(pullSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pullRobotAccountName, pullToken))) } It("should provision image repository for component, without update component annotation", func() { @@ -473,15 +435,10 @@ var _ = Describe("Image repository controller", func() { assertProvisionRepository(true) }) - It("should regenerate tokens and update remote secret", func() { + It("should regenerate tokens and update secrets", func() { newPushToken := "push-token5678" newPullToken := "pull-token5678" - pushUploadSecretKey := types.NamespacedName{Name: "upload-secret-" + resourceKey.Name + "-image-push", Namespace: resourceKey.Namespace} - pullUploadSecretKey := types.NamespacedName{Name: "upload-secret-" + resourceKey.Name + "-image-pull", Namespace: resourceKey.Namespace} - defer deleteSecret(pushUploadSecretKey) - defer deleteSecret(pullUploadSecretKey) - // Wait just for case it takes less than a second to regenerate credentials time.Sleep(time.Second) @@ -514,37 +471,33 @@ var _ = Describe("Image repository controller", func() { *imageRepository.Status.Credentials.GenerationTimestamp != oldTokenGenerationTimestamp }, timeout, interval).Should(BeTrue()) - pushRemoteSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PushRemoteSecretName, Namespace: imageRepository.Namespace} - pushRemoteSecret := waitRemoteSecretExist(pushRemoteSecretKey) + pushSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PushSecretName, Namespace: imageRepository.Namespace} + pushSecret := waitSecretExist(pushSecretKey) + defer deleteSecret(pushSecretKey) - pullRemoteSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PullRemoteSecretName, Namespace: imageRepository.Namespace} - pullRemoteSecret := waitRemoteSecretExist(pullRemoteSecretKey) + pullSecretKey := types.NamespacedName{Name: imageRepository.Status.Credentials.PullSecretName, Namespace: imageRepository.Namespace} + pullSecret := waitSecretExist(pullSecretKey) + defer deleteSecret(pullSecretKey) var authDataJson interface{} - pushUploadSecret := waitSecretExist(pushUploadSecretKey) - Expect(pushUploadSecret.Labels[remotesecretv1beta1.UploadSecretLabel]).To(Equal("remotesecret")) - Expect(pushUploadSecret.Annotations[remotesecretv1beta1.RemoteSecretNameAnnotation]).To(Equal(pushRemoteSecret.Name)) - Expect(pushUploadSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - pushUploadSecretDockerconfigJson := string(pushUploadSecret.Data[corev1.DockerConfigJsonKey]) - Expect(json.Unmarshal([]byte(pushUploadSecretDockerconfigJson), &authDataJson)).To(Succeed()) - Expect(pushUploadSecretDockerconfigJson).To(ContainSubstring(expectedImage)) - pushUploadSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pushUploadSecretDockerconfigJson)[1]) + Expect(pushSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) + pushSecretDockerconfigJson := string(pushSecret.Data[corev1.DockerConfigJsonKey]) + Expect(json.Unmarshal([]byte(pushSecretDockerconfigJson), &authDataJson)).To(Succeed()) + Expect(pushSecretDockerconfigJson).To(ContainSubstring(expectedImage)) + pushSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pushSecretDockerconfigJson)[1]) Expect(err).To(Succeed()) pushRobotAccountName := imageRepository.Status.Credentials.PushRobotAccountName - Expect(string(pushUploadSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pushRobotAccountName, newPushToken))) - - pullUploadSecret := waitSecretExist(pullUploadSecretKey) - Expect(pullUploadSecret.Labels[remotesecretv1beta1.UploadSecretLabel]).To(Equal("remotesecret")) - Expect(pullUploadSecret.Annotations[remotesecretv1beta1.RemoteSecretNameAnnotation]).To(Equal(pullRemoteSecret.Name)) - Expect(pullUploadSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - pullUploadSecretDockerconfigJson := string(pullUploadSecret.Data[corev1.DockerConfigJsonKey]) - Expect(json.Unmarshal([]byte(pullUploadSecretDockerconfigJson), &authDataJson)).To(Succeed()) - Expect(pullUploadSecretDockerconfigJson).To(ContainSubstring(expectedImage)) - pullUploadSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pullUploadSecretDockerconfigJson)[1]) + Expect(string(pushSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pushRobotAccountName, newPushToken))) + + Expect(pullSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) + pullSecretDockerconfigJson := string(pullSecret.Data[corev1.DockerConfigJsonKey]) + Expect(json.Unmarshal([]byte(pullSecretDockerconfigJson), &authDataJson)).To(Succeed()) + Expect(pullSecretDockerconfigJson).To(ContainSubstring(expectedImage)) + pullSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(pullSecretDockerconfigJson)[1]) Expect(err).To(Succeed()) pullRobotAccountName := imageRepository.Status.Credentials.PullRobotAccountName - Expect(string(pullUploadSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pullRobotAccountName, newPullToken))) + Expect(string(pullSecretAuthString)).To(Equal(fmt.Sprintf("%s:%s", pullRobotAccountName, newPullToken))) }) It("should cleanup component repository", func() { @@ -583,7 +536,6 @@ var _ = Describe("Image repository controller", func() { BeforeEach(func() { quay.ResetTestQuayClient() deleteImageRepository(resourceKey) - deleteUploadSecrets(defaultNamespace) }) It("should create image repository with requested name", func() { @@ -618,7 +570,6 @@ var _ = Describe("Image repository controller", func() { BeforeEach(func() { quay.ResetTestQuayClient() deleteImageRepository(resourceKey) - deleteUploadSecrets(defaultNamespace) }) It("should prepare environment", func() { diff --git a/controllers/imagerepository_controller_unit_test.go b/controllers/imagerepository_controller_unit_test.go index 4b0213e..54126d0 100644 --- a/controllers/imagerepository_controller_unit_test.go +++ b/controllers/imagerepository_controller_unit_test.go @@ -79,39 +79,39 @@ func TestGenerateQuayRobotAccountName(t *testing.T) { } } -func TestGetRemoteSecretName(t *testing.T) { +func TestGetSecretName(t *testing.T) { longImageRepositoryCrName := getRandomString(300) - expectedRemoteSecretLongPrefix := longImageRepositoryCrName[0:220] + expectedSecretLongPrefix := longImageRepositoryCrName[0:220] testCases := []struct { - name string - imageRepositoryCrName string - IsPullOnly bool - expectedRemoteSecretName string + name string + imageRepositoryCrName string + IsPullOnly bool + expectedSecretName string }{ { - name: "Should generate push remote secret name", - imageRepositoryCrName: "my-image-repo", - IsPullOnly: false, - expectedRemoteSecretName: "my-image-repo-image-push", + name: "Should generate push secret name", + imageRepositoryCrName: "my-image-repo", + IsPullOnly: false, + expectedSecretName: "my-image-repo-image-push", }, { - name: "Should generate push remote secret name if component name is too long", - imageRepositoryCrName: longImageRepositoryCrName, - IsPullOnly: false, - expectedRemoteSecretName: expectedRemoteSecretLongPrefix + "-image-push", + name: "Should generate push secret name if component name is too long", + imageRepositoryCrName: longImageRepositoryCrName, + IsPullOnly: false, + expectedSecretName: expectedSecretLongPrefix + "-image-push", }, { - name: "Should generate pull remote secret name", - imageRepositoryCrName: "my-image-repo", - IsPullOnly: true, - expectedRemoteSecretName: "my-image-repo-image-pull", + name: "Should generate pull secret name", + imageRepositoryCrName: "my-image-repo", + IsPullOnly: true, + expectedSecretName: "my-image-repo-image-pull", }, { - name: "Should generate pull remote secret name if component name is too long", - imageRepositoryCrName: longImageRepositoryCrName, - IsPullOnly: true, - expectedRemoteSecretName: expectedRemoteSecretLongPrefix + "-image-pull", + name: "Should generate pull secret name if component name is too long", + imageRepositoryCrName: longImageRepositoryCrName, + IsPullOnly: true, + expectedSecretName: expectedSecretLongPrefix + "-image-pull", }, } @@ -123,13 +123,13 @@ func TestGetRemoteSecretName(t *testing.T) { }, } - remoteSecretName := getRemoteSecretName(imageRepository, tc.IsPullOnly) + secretName := getSecretName(imageRepository, tc.IsPullOnly) - if len(remoteSecretName) > 253 { - t.Error("remote secret name is longer than allowed") + if len(secretName) > 253 { + t.Error("secret name is longer than allowed") } - if remoteSecretName != tc.expectedRemoteSecretName { - t.Errorf("Expected remote secret name %s, but got %s", tc.expectedRemoteSecretName, remoteSecretName) + if secretName != tc.expectedSecretName { + t.Errorf("Expected secret name %s, but got %s", tc.expectedSecretName, secretName) } }) } diff --git a/controllers/suite_test.go b/controllers/suite_test.go index efc2845..8e8bea8 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -39,7 +39,6 @@ import ( imagerepositoryv1alpha1 "github.com/konflux-ci/image-controller/api/v1alpha1" "github.com/konflux-ci/image-controller/pkg/quay" appstudioredhatcomv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" - remotesecretv1beta1 "github.com/redhat-appstudio/remote-secret/api/v1beta1" //+kubebuilder:scaffold:imports ) @@ -70,13 +69,11 @@ var _ = BeforeSuite(func() { By("bootstrapping test environment") applicationApiDepVersion := "v0.0.0-20231026192857-89515ad2504f" - remoteSecretApiDepVersion := "v0.0.0-20240103070316-c146261dd544" testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{ filepath.Join("..", "config", "crd", "bases"), filepath.Join(build.Default.GOPATH, "pkg", "mod", "github.com", "redhat-appstudio", "application-api@"+applicationApiDepVersion, "config", "crd", "bases"), - filepath.Join(build.Default.GOPATH, "pkg", "mod", "github.com", "redhat-appstudio", "remote-secret@"+remoteSecretApiDepVersion, "config", "crd", "bases"), }, ErrorIfCRDPathMissing: true, } @@ -92,9 +89,6 @@ var _ = BeforeSuite(func() { err = appstudioredhatcomv1alpha1.AddToScheme(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) - err = remotesecretv1beta1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - err = imagerepositoryv1alpha1.AddToScheme(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) diff --git a/controllers/suite_util_test.go b/controllers/suite_util_test.go index f72cfd3..289cdb8 100644 --- a/controllers/suite_util_test.go +++ b/controllers/suite_util_test.go @@ -21,19 +21,15 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" corev1 "k8s.io/api/core/v1" k8sErrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/types" imagerepositoryv1alpha1 "github.com/konflux-ci/image-controller/api/v1alpha1" appstudioapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" - remotesecretv1beta1 "github.com/redhat-appstudio/remote-secret/api/v1beta1" ) const ( @@ -344,25 +340,26 @@ func deleteSecret(resourceKey types.NamespacedName) { }, timeout, interval).Should(BeTrue()) } -func deleteUploadSecrets(namesapce string) { - uploadSecretRequirement, err := labels.NewRequirement(remotesecretv1beta1.UploadSecretLabel, selection.Equals, []string{"remotesecret"}) - Expect(err).ToNot(HaveOccurred()) - uploadSecretsSelector := labels.NewSelector().Add(*uploadSecretRequirement) - uploadSecretsListOptions := client.ListOptions{ - LabelSelector: uploadSecretsSelector, - Namespace: namesapce, - } - deleteOptions := &client.DeleteAllOfOptions{ - ListOptions: uploadSecretsListOptions, +func createServiceAccount(namespace, name string) corev1.ServiceAccount { + serviceAccount := corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, } - Expect(k8sClient.DeleteAllOf(ctx, &corev1.Secret{}, deleteOptions)).To(Succeed()) + Expect(k8sClient.Create(ctx, &serviceAccount)).To(Succeed()) + return getServiceAccount(namespace, name) } -func waitRemoteSecretExist(remoteSecretKey types.NamespacedName) *remotesecretv1beta1.RemoteSecret { - remoteSecret := &remotesecretv1beta1.RemoteSecret{} +func getServiceAccount(namespace string, name string) corev1.ServiceAccount { + sa := corev1.ServiceAccount{} + key := types.NamespacedName{ + Namespace: namespace, + Name: name, + } Eventually(func() bool { - err := k8sClient.Get(ctx, remoteSecretKey, remoteSecret) - return err == nil && remoteSecret.ResourceVersion != "" + Expect(k8sClient.Get(ctx, key, &sa)).To(Succeed()) + return sa.ResourceVersion != "" }, timeout, interval).Should(BeTrue()) - return remoteSecret + return sa } diff --git a/go.mod b/go.mod index f1bb949..51f6557 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/onsi/gomega v1.30.0 github.com/prometheus/client_golang v1.18.0 github.com/redhat-appstudio/application-api v0.0.0-20231026192857-89515ad2504f - github.com/redhat-appstudio/remote-secret v0.0.0-20240103070316-c146261dd544 go.uber.org/zap v1.26.0 gotest.tools/v3 v3.5.0 k8s.io/api v0.29.0 diff --git a/hack/remove_rs.sh b/hack/remove_rs.sh new file mode 100755 index 0000000..78986ec --- /dev/null +++ b/hack/remove_rs.sh @@ -0,0 +1,56 @@ +#/bin/bash + +IFS=$'\n' LIST=( $(kubectl get remotesecrets -L appstudio.redhat.com/internal -A -o custom-columns=":metadata.namespace,:metadata.name" --no-headers | grep "\-pull\|\-push") ) +IFS=' ' +for QN in "${LIST[@]}"; do + read -ra ARR <<< "$QN" + NS=${ARR[0]} + NAME=${ARR[1]} + + # read remotesecret json + RSJSON=$(kubectl get remotesecret "${NAME}" -n ${NS} -o json) + + # preserve ownerReferences + OWNREF=$(echo $RSJSON | jq '[ .metadata.ownerReferences[]]') + OREF_PATCH="{\"metadata\":{\"ownerReferences\":$OWNREF}}" + # echo $OREF_PATCH + + # read secret json + SJSON=$(kubectl get secret ${NAME} -n ${NS} -o json) + if [[ -z $SJSON ]]; then + echo "Secret $NS/$NAME not found. Data not exists? Continue." + continue + fi + + # delete remotesecret + if kubectl delete remotesecret ${NAME} -n ${NS} + then + echo "RS $NS/$NAME removed OK" + else + echo "Failed to delete RemoteSecret $NS/$NAME. Exiting" + exit 1 + fi + + # re-create secret from json + if echo $SJSON | kubectl create -f - + then + echo "Secret $NS/$NAME re-created OK" + else + echo "Failed to re-create Secret $NS/$NAME. Exiting" + exit 1 + fi + + # patch ownerReferences in the secret by saved one + if kubectl patch secret ${NAME} -n ${NS} -p "${OREF_PATCH}" --type="merge" + then + echo "Secret $NS/$NAME owner ref patched OK" + else + echo "Failed to patch Secret $NS/$NAME owner ref. Exiting" + exit 1 + fi + + # remove redundant labels/annotations + kubectl label secret $NAME -n $NS appstudio.redhat.com/linked-by-remote-secret- + kubectl annotate secret $NAME -n $NS appstudio.redhat.com/linked-remote-secrets- + kubectl annotate secret $NAME -n $NS appstudio.redhat.com/managing-remote-secret- +done \ No newline at end of file diff --git a/main.go b/main.go index 895be61..ec1cb0f 100644 --- a/main.go +++ b/main.go @@ -43,7 +43,6 @@ import ( "github.com/go-logr/logr" "github.com/konflux-ci/image-controller/pkg/metrics" appstudioredhatcomv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" - remotesecretv1beta1 "github.com/redhat-appstudio/remote-secret/api/v1beta1" cmetrics "sigs.k8s.io/controller-runtime/pkg/metrics" imagerepositoryv1alpha1 "github.com/konflux-ci/image-controller/api/v1alpha1" @@ -66,7 +65,6 @@ func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(appstudioredhatcomv1alpha1.AddToScheme(scheme)) - utilruntime.Must(remotesecretv1beta1.AddToScheme(scheme)) utilruntime.Must(imagerepositoryv1alpha1.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme }