diff --git a/internal/controller/basic_authenticator/basicauthenticator_controller.go b/internal/controller/basic_authenticator/basicauthenticator_controller.go index f2413f8..0029109 100644 --- a/internal/controller/basic_authenticator/basicauthenticator_controller.go +++ b/internal/controller/basic_authenticator/basicauthenticator_controller.go @@ -19,10 +19,12 @@ package basic_authenticator import ( "context" "github.com/go-logr/logr" + "github.com/opdev/subreconciler" authenticatorv1alpha1 "github.com/snapp-incubator/simple-authenticator/api/v1alpha1" "github.com/snapp-incubator/simple-authenticator/internal/config" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -59,6 +61,19 @@ func (r *BasicAuthenticatorReconciler) Reconcile(ctx context.Context, req ctrl.R r.logger.Info("reconcile triggered") r.logger.Info(req.String()) r.initVars(req) + + basicAuthenticator := &authenticatorv1alpha1.BasicAuthenticator{} + switch err := r.Get(ctx, req.NamespacedName, basicAuthenticator); { + case errors.IsNotFound(err): + return r.Cleanup(ctx, req) + case err != nil: + r.logger.Error(err, "failed to fetch object") + return subreconciler.Evaluate(subreconciler.Requeue()) + default: + if basicAuthenticator.ObjectMeta.DeletionTimestamp != nil { + return r.Cleanup(ctx, req) + } + } return r.Provision(ctx, req) } diff --git a/internal/controller/basic_authenticator/cleanup.go b/internal/controller/basic_authenticator/cleanup.go new file mode 100644 index 0000000..8fee8b2 --- /dev/null +++ b/internal/controller/basic_authenticator/cleanup.go @@ -0,0 +1,180 @@ +package basic_authenticator + +import ( + "context" + "errors" + "github.com/opdev/subreconciler" + "github.com/snapp-incubator/simple-authenticator/api/v1alpha1" + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +func (r *BasicAuthenticatorReconciler) Cleanup(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + // Do the actual reconcile work + subRecs := []subreconciler.FnWithRequest{ + r.setDeletionStatus, + r.removeInjectedContainers, + r.removeCleanupFinalizer, + } + for _, rec := range subRecs { + result, err := rec(ctx, req) + if subreconciler.ShouldHaltOrRequeue(result, err) { + return subreconciler.Evaluate(result, err) + } + } + + return subreconciler.Evaluate(subreconciler.DoNotRequeue()) +} +func (r *BasicAuthenticatorReconciler) setDeletionStatus(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { + basicAuthenticator := &v1alpha1.BasicAuthenticator{} + if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { + return subreconciler.RequeueWithError(err) + } + basicAuthenticator.Status.State = StatusDeleting + + if err := r.Update(ctx, basicAuthenticator); err != nil { + r.logger.Error(err, "Failed to update status while cleaning") + return subreconciler.RequeueWithError(err) + } + return subreconciler.ContinueReconciling() +} +func (r *BasicAuthenticatorReconciler) removeInjectedContainers(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { + basicAuthenticator := &v1alpha1.BasicAuthenticator{} + + if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { + return subreconciler.RequeueWithError(err) + } + + if basicAuthenticator.Spec.Type != "sidecar" { + return subreconciler.ContinueReconciling() + } + basicAuthLabel := map[string]string{ + basicAuthenticatorNameLabel: basicAuthenticator.Name, + } + deployments, err := getTargetDeployment(ctx, basicAuthenticator, r.Client, basicAuthLabel) + if err != nil { + r.logger.Error(err, "failed to get target deployments to clean up") + return subreconciler.RequeueWithError(err) + } + configmaps, err := getTargetConfigmapNames(ctx, basicAuthenticator, r.Client, basicAuthLabel) + if err != nil { + r.logger.Error(err, "failed to get target configmap to clean up") + return subreconciler.RequeueWithError(err) + } + secrets, err := getTargetSecretName(ctx, basicAuthenticator, r.Client, basicAuthLabel) + if err != nil { + r.logger.Error(err, "failed to get target secret to clean up") + return subreconciler.RequeueWithError(err) + } + r.logger.Info("debug", "configmap", configmaps, "secret", secrets) + + cleanupDeployments := removeInjectedResources(deployments, secrets, configmaps) + for _, deploy := range cleanupDeployments { + if err := r.Update(ctx, deploy); err != nil { + r.logger.Error(err, "failed to add update cleaned up deployments") + return subreconciler.RequeueWithError(err) + } + } + return subreconciler.ContinueReconciling() +} +func (r *BasicAuthenticatorReconciler) removeCleanupFinalizer(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { + basicAuthenticator := &v1alpha1.BasicAuthenticator{} + if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { + return subreconciler.RequeueWithError(err) + } + if controllerutil.ContainsFinalizer(basicAuthenticator, basicAuthenticatorFinalizer) { + if ok := controllerutil.RemoveFinalizer(basicAuthenticator, basicAuthenticatorFinalizer); !ok { + r.logger.Error(errors.New("finalizer not updated"), "Failed to remove finalizer for BasicAuthenticator") + return subreconciler.Requeue() + } + } + + if err := r.Update(ctx, basicAuthenticator); err != nil { + r.logger.Error(err, "Failed to remove finalizer for BasicAuthenticator") + return subreconciler.RequeueWithError(err) + } + return subreconciler.ContinueReconciling() +} + +func getTargetDeployment(ctx context.Context, basicAuthenticator *v1alpha1.BasicAuthenticator, k8Client client.Client, basicAuthLabels map[string]string) ([]*appsv1.Deployment, error) { + var deploymentList appsv1.DeploymentList + if err := k8Client.List( + ctx, + &deploymentList, + client.MatchingLabelsSelector{Selector: labels.SelectorFromSet(basicAuthLabels)}, + client.InNamespace(basicAuthenticator.Namespace)); err != nil { + return nil, err + } + + resultDeployments := make([]*appsv1.Deployment, 0) + for _, deploy := range deploymentList.Items { + resultDeployments = append(resultDeployments, &deploy) + } + return resultDeployments, nil +} +func getTargetConfigmapNames(ctx context.Context, basicAuthenticator *v1alpha1.BasicAuthenticator, k8Client client.Client, basicAuthLabels map[string]string) ([]string, error) { + var configMapList v1.ConfigMapList + if err := k8Client.List( + ctx, + &configMapList, + client.MatchingLabelsSelector{Selector: labels.SelectorFromSet(basicAuthLabels)}, + client.InNamespace(basicAuthenticator.Namespace)); err != nil { + return nil, err + } + resultConfigMaps := make([]string, 0) + for _, cm := range configMapList.Items { + resultConfigMaps = append(resultConfigMaps, cm.Name) + } + return resultConfigMaps, nil +} +func getTargetSecretName(ctx context.Context, basicAuthenticator *v1alpha1.BasicAuthenticator, k8Client client.Client, basicAuthLabels map[string]string) ([]string, error) { + var secretList v1.SecretList + if err := k8Client.List( + ctx, + &secretList, + client.MatchingLabelsSelector{Selector: labels.SelectorFromSet(basicAuthLabels)}, + client.InNamespace(basicAuthenticator.Namespace)); err != nil { + return nil, err + } + + resultSecrets := make([]string, 0) + for _, sec := range secretList.Items { + resultSecrets = append(resultSecrets, sec.Name) + } + return resultSecrets, nil +} +func removeInjectedResources(deployments []*appsv1.Deployment, secrets []string, configmap []string) []*appsv1.Deployment { + for _, deploy := range deployments { + containers := make([]v1.Container, 0) + for _, container := range deploy.Spec.Template.Spec.Containers { + if container.Name != nginxDefaultContainerName { + containers = append(containers, container) + } + } + deploy.Spec.Template.Spec.Containers = containers + volumes := make([]v1.Volume, 0) + for _, vol := range deploy.Spec.Template.Spec.Volumes { + if !existsInList(secrets, vol.Name) && !existsInList(configmap, vol.Name) { + volumes = append(volumes, vol) + } + } + deploy.Spec.Template.Spec.Volumes = volumes + if deploy.Labels != nil { + delete(deploy.Labels, basicAuthenticatorNameLabel) + } + } + return deployments +} + +func existsInList(strList []string, targetStr string) bool { + for _, val := range strList { + if val == targetStr { + return true + } + } + return false +} diff --git a/internal/controller/basic_authenticator/const.go b/internal/controller/basic_authenticator/const.go index 67abd9f..3b7c530 100644 --- a/internal/controller/basic_authenticator/const.go +++ b/internal/controller/basic_authenticator/const.go @@ -3,8 +3,7 @@ package basic_authenticator const ( nginxDefaultImageAddress = "nginx:1.25.3" nginxDefaultContainerName = "nginx" - SecretAnnotation = "authenticator.snappcloud.io/secret.name" - ConfigmapAnnotation = "authenticator.snappcloud.io/configmap.name" + basicAuthenticatorNameLabel = "basicauthenticator.snappcloud.io/name" basicAuthenticatorFinalizer = "basicauthenticator.snappcloud.io/finalizer" ExternallyManaged = "basicauthenticator.snappcloud.io/externally.managed" ConfigMountPath = "/etc/nginx/conf.d" @@ -15,7 +14,6 @@ const ( template = `server { listen AUTHENTICATOR_PORT; location / { - resolver 8.8.8.8; auth_basic "basic authentication area"; auth_basic_user_file "FILE_PATH"; proxy_pass http://APP_SERVICE:APP_PORT; @@ -25,4 +23,7 @@ const ( proxy_set_header X-Forwarded-Proto $scheme; } }` + StatusAvailable = "Available" + StatusReconciling = "Reconciling" + StatusDeleting = "Deleting" ) diff --git a/internal/controller/basic_authenticator/provision.go b/internal/controller/basic_authenticator/provision.go index b1829b0..fe68ebc 100644 --- a/internal/controller/basic_authenticator/provision.go +++ b/internal/controller/basic_authenticator/provision.go @@ -13,16 +13,20 @@ import ( "reflect" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) // Provision provisions the required resources for the basicAuthenticator object func (r *BasicAuthenticatorReconciler) Provision(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Do the actual reconcile work subProvisioner := []subreconciler.FnWithRequest{ + r.setReconcilingStatus, + r.addCleanupFinalizer, r.ensureSecret, r.ensureConfigmap, r.ensureDeployment, r.ensureService, + r.setAvailableStatus, } for _, provisioner := range subProvisioner { result, err := provisioner(ctx, req) @@ -33,6 +37,37 @@ func (r *BasicAuthenticatorReconciler) Provision(ctx context.Context, req ctrl.R return subreconciler.Evaluate(subreconciler.DoNotRequeue()) } +func (r *BasicAuthenticatorReconciler) setReconcilingStatus(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { + basicAuthenticator := &v1alpha1.BasicAuthenticator{} + + if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { + return subreconciler.RequeueWithError(err) + } + + basicAuthenticator.Status.State = StatusReconciling + if err := r.Update(ctx, basicAuthenticator); err != nil { + r.logger.Error(err, "failed to update status") + return subreconciler.Requeue() + } + return subreconciler.ContinueReconciling() +} + +func (r *BasicAuthenticatorReconciler) addCleanupFinalizer(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { + basicAuthenticator := &v1alpha1.BasicAuthenticator{} + + if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { + return subreconciler.RequeueWithError(err) + } + if !controllerutil.ContainsFinalizer(basicAuthenticator, basicAuthenticatorFinalizer) { + if objUpdated := controllerutil.AddFinalizer(basicAuthenticator, basicAuthenticatorFinalizer); objUpdated { + if err := r.Update(ctx, basicAuthenticator); err != nil { + r.logger.Error(err, "failed to add basicAuthenticator finalizer") + return subreconciler.Requeue() + } + } + } + return subreconciler.ContinueReconciling() +} func (r *BasicAuthenticatorReconciler) getLatestBasicAuthenticator(ctx context.Context, req ctrl.Request, basicAuthenticator *v1alpha1.BasicAuthenticator) (*ctrl.Result, error) { err := r.Get(ctx, req.NamespacedName, basicAuthenticator) @@ -51,7 +86,7 @@ func (r *BasicAuthenticatorReconciler) ensureSecret(ctx context.Context, req ctr basicAuthenticator := &v1alpha1.BasicAuthenticator{} if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { - return r, err + return subreconciler.RequeueWithError(err) } r.credentialName = basicAuthenticator.Spec.CredentialsSecretRef var credentialSecret corev1.Secret @@ -118,7 +153,7 @@ func (r *BasicAuthenticatorReconciler) ensureConfigmap(ctx context.Context, req basicAuthenticator := &v1alpha1.BasicAuthenticator{} if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { - return r, err + return subreconciler.RequeueWithError(err) } authenticatorConfig := createNginxConfigmap(basicAuthenticator) @@ -160,7 +195,7 @@ func (r *BasicAuthenticatorReconciler) ensureDeployment(ctx context.Context, req basicAuthenticator := &v1alpha1.BasicAuthenticator{} if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { - return r, err + return subreconciler.RequeueWithError(err) } if r.configMapName == "" { @@ -182,7 +217,7 @@ func (r *BasicAuthenticatorReconciler) ensureService(ctx context.Context, req ct basicAuthenticator := &v1alpha1.BasicAuthenticator{} if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { - return r, err + return subreconciler.RequeueWithError(err) } if r.deploymentLabel == nil { return subreconciler.ContinueReconciling() @@ -217,6 +252,22 @@ func (r *BasicAuthenticatorReconciler) ensureService(ctx context.Context, req ct } return subreconciler.ContinueReconciling() } + +func (r *BasicAuthenticatorReconciler) setAvailableStatus(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { + basicAuthenticator := &v1alpha1.BasicAuthenticator{} + + if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { + return subreconciler.RequeueWithError(err) + } + + basicAuthenticator.Status.State = StatusAvailable + if err := r.Update(ctx, basicAuthenticator); err != nil { + r.logger.Error(err, "failed to update status") + return subreconciler.Requeue() + } + return subreconciler.ContinueReconciling() +} + func (r *BasicAuthenticatorReconciler) createDeploymentAuthenticator(ctx context.Context, req ctrl.Request, basicAuthenticator *v1alpha1.BasicAuthenticator, authenticatorConfigName, secretName string) (*ctrl.Result, error) { newDeployment := createNginxDeployment(basicAuthenticator, authenticatorConfigName, secretName, r.CustomConfig) @@ -253,6 +304,7 @@ func (r *BasicAuthenticatorReconciler) createDeploymentAuthenticator(ctx context replica, err := r.acquireTargetReplica(ctx, basicAuthenticator) if err != nil { r.logger.Error(err, "failed to acquire target replica using adaptiveScale") + return subreconciler.RequeueWithError(err) } targetReplica = &replica } @@ -262,8 +314,7 @@ func (r *BasicAuthenticatorReconciler) createDeploymentAuthenticator(ctx context foundDeployment.Spec = newDeployment.Spec foundDeployment.Spec.Replicas = targetReplica - - err := r.Update(ctx, foundDeployment) + err = r.Update(ctx, foundDeployment) if err != nil { r.logger.Error(err, "failed to update deployment") return subreconciler.RequeueWithError(err) @@ -271,7 +322,7 @@ func (r *BasicAuthenticatorReconciler) createDeploymentAuthenticator(ctx context } r.logger.Info("updating ready replicas") basicAuthenticator.Status.ReadyReplicas = int(foundDeployment.Status.ReadyReplicas) - err := r.Status().Update(ctx, basicAuthenticator) + err = r.Status().Update(ctx, basicAuthenticator) if err != nil { r.logger.Error(err, "failed to update basic authenticator status") return subreconciler.RequeueWithError(err) @@ -287,10 +338,6 @@ func (r *BasicAuthenticatorReconciler) createSidecarAuthenticator(ctx context.Co return subreconciler.RequeueWithError(err) } for _, deploy := range deploymentsToUpdate { - if err := ctrl.SetControllerReference(basicAuthenticator, deploy, r.Scheme); err != nil { - r.logger.Error(err, "failed to set injected deployment owner") - return subreconciler.RequeueWithError(err) - } err := r.Update(ctx, deploy) if err != nil { r.logger.Error(err, "failed to update injected deployments") diff --git a/internal/controller/basic_authenticator/workload.go b/internal/controller/basic_authenticator/workload.go index de7ed39..5c452b4 100644 --- a/internal/controller/basic_authenticator/workload.go +++ b/internal/controller/basic_authenticator/workload.go @@ -27,7 +27,7 @@ func createNginxDeployment(basicAuthenticator *v1alpha1.BasicAuthenticator, conf replicas := int32(basicAuthenticator.Spec.Replicas) authenticatorPort := int32(basicAuthenticator.Spec.AuthenticatorPort) - basicAuthLabels := map[string]string{"app": deploymentName} + basicAuthLabels := map[string]string{"app": deploymentName, basicAuthenticatorNameLabel: basicAuthenticator.Name} //TODO: mount secret as volume deploy := &appsv1.Deployment{ @@ -97,7 +97,7 @@ func createNginxDeployment(basicAuthenticator *v1alpha1.BasicAuthenticator, conf func createNginxConfigmap(basicAuthenticator *v1alpha1.BasicAuthenticator) *corev1.ConfigMap { configmapName := random_generator.GenerateRandomName(basicAuthenticator.Name, "configmap") basicAuthLabels := map[string]string{ - "app": basicAuthenticator.Name, + basicAuthenticatorNameLabel: basicAuthenticator.Name, } nginxConf := fillTemplate(template, SecretMountPath, basicAuthenticator) data := map[string]string{ @@ -140,11 +140,15 @@ func createCredentials(basicAuthenticator *v1alpha1.BasicAuthenticator) (*corev1 if err != nil { return nil, errors.Wrap(err, "failed to generate salt") } + basicAuthLabels := map[string]string{ + basicAuthenticatorNameLabel: basicAuthenticator.Name, + } secretName := random_generator.GenerateRandomName(basicAuthenticator.Name, salt) secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: secretName, Namespace: basicAuthenticator.Namespace, + Labels: basicAuthLabels, }, Data: map[string][]byte{ "username": []byte(username), @@ -157,10 +161,14 @@ func createNginxService(ctx context.Context, basicAuthenticator *v1alpha1.BasicA serviceName := fmt.Sprintf("%s-svc", basicAuthenticator.Name) serviceType := getServiceType(basicAuthenticator.Spec.ServiceType) targetPort := intstr.IntOrString{Type: intstr.Int, IntVal: int32(basicAuthenticator.Spec.AuthenticatorPort)} + basicAuthLabel := map[string]string{ + basicAuthenticatorNameLabel: basicAuthenticator.Name, + } svc := corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: serviceName, Namespace: basicAuthenticator.Namespace, + Labels: basicAuthLabel, }, Spec: corev1.ServiceSpec{ Selector: selector.MatchLabels, @@ -192,53 +200,52 @@ func injector(ctx context.Context, basicAuthenticator *v1alpha1.BasicAuthenticat resultDeployments := make([]*appsv1.Deployment, 0) for _, deployment := range deploymentList.Items { - // we can use revision number to update container config - _, isInjected := deployment.ObjectMeta.Annotations["basic.authenticator.inject/revision"] - if isInjected { - continue + if deployment.Labels == nil { + deployment.Labels = make(map[string]string) } - deployment.ObjectMeta.Annotations = map[string]string{ - "basic.authenticator.inject/revision": "1", - } - - deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, corev1.Container{ - Name: nginxContainerName, - Image: nginxImageAddress, - Ports: []corev1.ContainerPort{ - { - ContainerPort: authenticatorPort, - }, - }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: configMapName, - MountPath: ConfigMountPath, + deployment.Labels[basicAuthenticatorNameLabel] = basicAuthenticator.Name + idx := getContainerIndex(deployment.Spec.Template.Spec.Containers, nginxContainerName) + if idx == -1 { // meaning its the first time creating container + deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, corev1.Container{ + Name: nginxContainerName, + Image: nginxImageAddress, + Ports: []corev1.ContainerPort{ + { + ContainerPort: authenticatorPort, + }, }, - { - Name: credentialName, - MountPath: SecretMountDir, - SubPath: SecretHtpasswdField, + VolumeMounts: []corev1.VolumeMount{ + { + Name: configMapName, + MountPath: ConfigMountPath, + }, + { + Name: credentialName, + MountPath: SecretMountDir, + SubPath: SecretHtpasswdField, + }, }, - }, - }) - deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, corev1.Volume{ - Name: configMapName, - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: configMapName, + }) + deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, corev1.Volume{ + Name: configMapName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: configMapName, + }, }, }, - }, - }) - deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, corev1.Volume{ - Name: credentialName, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: credentialName, + }) + deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, corev1.Volume{ + Name: credentialName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: credentialName, + }, }, - }, - }) + }) + } //TODO: handling config change later (idx >=0) + resultDeployments = append(resultDeployments, &deployment) } return resultDeployments, nil @@ -269,3 +276,12 @@ func getServiceType(serviceType string) corev1.ServiceType { return corev1.ServiceTypeClusterIP } } + +func getContainerIndex(containers []corev1.Container, name string) int { + for idx, container := range containers { + if container.Name == name { + return idx + } + } + return -1 +} diff --git a/tests/e2e/adaptive-scaling/00-install.yaml b/tests/e2e/adaptive-scaling/00-install.yaml index 6b23552..67be0d5 100644 --- a/tests/e2e/adaptive-scaling/00-install.yaml +++ b/tests/e2e/adaptive-scaling/00-install.yaml @@ -10,7 +10,7 @@ metadata: name: basicauthenticator-sample spec: type: deployment - replicas: 1 + replicas: 2 appPort: 8080 appService: my-service adaptiveScale: true @@ -36,6 +36,7 @@ spec: containers: - name: curl-container image: curlimages/curl:latest + imagePullPolicy: IfNotPresent command: ["sleep", "infinity"] --- apiVersion: v1 diff --git a/tests/e2e/cleanup/00-assert.yaml b/tests/e2e/cleanup/00-assert.yaml new file mode 100644 index 0000000..31b57b6 --- /dev/null +++ b/tests/e2e/cleanup/00-assert.yaml @@ -0,0 +1,8 @@ +apiVersion: authenticator.snappcloud.io/v1alpha1 +kind: BasicAuthenticator +metadata: + name: basicauthenticator-sample-deployment + namespace: cleanup +status: + readyReplicas: 2 + diff --git a/tests/e2e/cleanup/00-install.yaml b/tests/e2e/cleanup/00-install.yaml new file mode 100644 index 0000000..be78624 --- /dev/null +++ b/tests/e2e/cleanup/00-install.yaml @@ -0,0 +1,61 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: cleanup +--- +apiVersion: authenticator.snappcloud.io/v1alpha1 +kind: BasicAuthenticator +metadata: + labels: + app.kubernetes.io/name: basicauthenticator + app.kubernetes.io/instance: basicauthenticator-sample + app.kubernetes.io/part-of: basicauthenticator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: basicauthenticator + name: basicauthenticator-sample-deployment + namespace: cleanup +spec: + type: deployment + replicas: 2 + selector: + matchLabels: + foo: bar + appPort: 8080 + appService: google.com + adaptiveScale: false + authenticatorPort: 8080 +--- +apiVersion: authenticator.snappcloud.io/v1alpha1 +kind: BasicAuthenticator +metadata: + name: basicauthenticator-sample-sidecar + namespace: cleanup +spec: + type: sidecar + selector: + matchLabels: + foo: bar + appPort: 8080 + authenticatorPort: 8080 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: curl-deployment + namespace: cleanup + labels: + foo: bar +spec: + replicas: 1 + selector: + matchLabels: + foo: bar + template: + metadata: + labels: + foo: bar + spec: + containers: + - name: curl-container + image: curlimages/curl:latest + command: ["sleep", "infinity"] \ No newline at end of file diff --git a/tests/e2e/cleanup/01-assert.yaml b/tests/e2e/cleanup/01-assert.yaml new file mode 100644 index 0000000..6c6844e --- /dev/null +++ b/tests/e2e/cleanup/01-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 30 +commands: + - script: | + count=$(kubectl get cm,deploy,secret,basicauthenticators.authenticator.snappcloud.io -n cleanup | grep basicauthenticator-sample-deployment | wc -l) + if [ "$count" -gt 0 ]; then + echo "Resources exist. Count: $count" + exit 2 + fi + exit 0 \ No newline at end of file diff --git a/tests/e2e/cleanup/01-delete-deployment.yaml b/tests/e2e/cleanup/01-delete-deployment.yaml new file mode 100644 index 0000000..037c717 --- /dev/null +++ b/tests/e2e/cleanup/01-delete-deployment.yaml @@ -0,0 +1,7 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: authenticator.snappcloud.io/v1alpha1 + kind: BasicAuthenticator + name: basicauthenticator-sample-deployment + namespace: cleanup diff --git a/tests/e2e/cleanup/02-assert.yaml b/tests/e2e/cleanup/02-assert.yaml new file mode 100644 index 0000000..a809d82 --- /dev/null +++ b/tests/e2e/cleanup/02-assert.yaml @@ -0,0 +1,30 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +timeout: 10 +commands: + - script: | + count=$(kubectl get cm,deploy,secret,basicauthenticators.authenticator.snappcloud.io,svc -n cleanup | grep basicauthenticator-sample-sidecar | wc -l) + if [ "$count" -gt 0 ]; then + echo "Resources exist. Count: $count" + exit 1 + fi + exit 0 + - script: | + deployment_name="curl-deployment" + namespace="cleanup" + + deployment_yaml=$(kubectl get deployment "$deployment_name" -n "$namespace" -o yaml) + + if [ -z "$deployment_yaml" ]; then + echo "Error: Deployment not found." + exit 1 + fi + + if echo "$deployment_yaml" | grep -q "basicauthenticator.snappcloud.io/name" && + echo "$deployment_yaml" | grep -q "basicauthenticator-sample-sidecar"; then + echo "labels and configs exist in the deployment YAML." + exit 1 + else + echo "successfully deleted" + exit 0 + fi diff --git a/tests/e2e/cleanup/02-delete-sidecar.yaml b/tests/e2e/cleanup/02-delete-sidecar.yaml new file mode 100644 index 0000000..afdf3e6 --- /dev/null +++ b/tests/e2e/cleanup/02-delete-sidecar.yaml @@ -0,0 +1,7 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: authenticator.snappcloud.io/v1alpha1 + kind: BasicAuthenticator + name: basicauthenticator-sample-sidecar + namespace: cleanup diff --git a/tests/e2e/sidecar/00-assert.yaml b/tests/e2e/sidecar/00-assert.yaml index 41e265f..f1291c3 100644 --- a/tests/e2e/sidecar/00-assert.yaml +++ b/tests/e2e/sidecar/00-assert.yaml @@ -4,5 +4,4 @@ metadata: name: curl-deployment labels: foo: bar - annotations: - basic.authenticator.inject/revision: "1" + basicauthenticator.snappcloud.io/name: basicauthenticator-sidecar