From 632e93d604e9eb9fcc39b543f7e843ba4143754c Mon Sep 17 00:00:00 2001 From: Claudio Netto Date: Wed, 17 May 2023 15:18:02 -0300 Subject: [PATCH] feat: drop support of Nginx cache sync --- api/v1alpha1/rpaasplan_types.go | 4 - api/v1alpha1/zz_generated.deepcopy.go | 2 - cmd/plugin/rpaasv2/cmd/info_test.go | 2 - .../extensions.tsuru.io_rpaasflavors.yaml | 42 --- .../extensions.tsuru.io_rpaasinstances.yaml | 42 --- .../bases/extensions.tsuru.io_rpaasplans.yaml | 40 -- controllers/controller.go | 313 +--------------- controllers/controller_test.go | 351 ------------------ controllers/rpaasinstance_controller.go | 4 - 9 files changed, 3 insertions(+), 797 deletions(-) diff --git a/api/v1alpha1/rpaasplan_types.go b/api/v1alpha1/rpaasplan_types.go index 4a0dcdaa5..aaaabe46a 100644 --- a/api/v1alpha1/rpaasplan_types.go +++ b/api/v1alpha1/rpaasplan_types.go @@ -66,10 +66,6 @@ type NginxConfig struct { CacheSize *resource.Quantity `json:"cacheSize,omitempty"` CacheZoneSize *resource.Quantity `json:"cacheZoneSize,omitempty"` - CacheSnapshotEnabled bool `json:"cacheSnapshotEnabled,omitempty"` - CacheSnapshotStorage CacheSnapshotStorage `json:"cacheSnapshotStorage,omitempty"` - CacheSnapshotSync CacheSnapshotSyncSpec `json:"cacheSnapshotSync,omitempty"` - LogFormat string `json:"logFormat,omitempty"` LogFormatEscape string `json:"logFormatEscape,omitempty"` LogFormatName string `json:"logFormatName,omitempty"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 6e4b9fbe9..730c8c081 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -232,8 +232,6 @@ func (in *NginxConfig) DeepCopyInto(out *NginxConfig) { x := (*in).DeepCopy() *out = &x } - in.CacheSnapshotStorage.DeepCopyInto(&out.CacheSnapshotStorage) - in.CacheSnapshotSync.DeepCopyInto(&out.CacheSnapshotSync) if in.LogAdditionalHeaders != nil { in, out := &in.LogAdditionalHeaders, &out.LogAdditionalHeaders *out = make([]string, len(*in)) diff --git a/cmd/plugin/rpaasv2/cmd/info_test.go b/cmd/plugin/rpaasv2/cmd/info_test.go index 1dc91eaf7..a07c75074 100644 --- a/cmd/plugin/rpaasv2/cmd/info_test.go +++ b/cmd/plugin/rpaasv2/cmd/info_test.go @@ -338,8 +338,6 @@ Plan overrides: "image": "registry.example.com/my/repository/nginx:v1", "config": { "cacheEnabled": false, - "cacheSnapshotStorage": {}, - "cacheSnapshotSync": {}, "workerProcesses": 4, "workerConnections": 4096 }, diff --git a/config/crd/bases/extensions.tsuru.io_rpaasflavors.yaml b/config/crd/bases/extensions.tsuru.io_rpaasflavors.yaml index cf324875c..e893d5223 100644 --- a/config/crd/bases/extensions.tsuru.io_rpaasflavors.yaml +++ b/config/crd/bases/extensions.tsuru.io_rpaasflavors.yaml @@ -422,48 +422,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - cacheSnapshotEnabled: - type: boolean - cacheSnapshotStorage: - properties: - storageClassName: - type: string - storageSize: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - volumeLabels: - additionalProperties: - type: string - type: object - type: object - cacheSnapshotSync: - properties: - cmdPVCToPod: - description: CmdPVCToPod is used to customize command - used to sync persistent storage (PVC) to memory - cache (POD) - items: - type: string - type: array - cmdPodToPVC: - description: CmdPodToPVC is used to customize command - used to sync memory cache (POD) to persistent storage - (PVC) - items: - type: string - type: array - image: - description: Container is the image used to sync the - containers default is bitnami/kubectl:latest - type: string - schedule: - description: Schedule is the the cron time string - format, see https://en.wikipedia.org/wiki/Cron. - type: string - type: object cacheZoneSize: anyOf: - type: integer diff --git a/config/crd/bases/extensions.tsuru.io_rpaasinstances.yaml b/config/crd/bases/extensions.tsuru.io_rpaasinstances.yaml index 98e025092..41a46cb48 100644 --- a/config/crd/bases/extensions.tsuru.io_rpaasinstances.yaml +++ b/config/crd/bases/extensions.tsuru.io_rpaasinstances.yaml @@ -398,48 +398,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - cacheSnapshotEnabled: - type: boolean - cacheSnapshotStorage: - properties: - storageClassName: - type: string - storageSize: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - volumeLabels: - additionalProperties: - type: string - type: object - type: object - cacheSnapshotSync: - properties: - cmdPVCToPod: - description: CmdPVCToPod is used to customize command - used to sync persistent storage (PVC) to memory cache - (POD) - items: - type: string - type: array - cmdPodToPVC: - description: CmdPodToPVC is used to customize command - used to sync memory cache (POD) to persistent storage - (PVC) - items: - type: string - type: array - image: - description: Container is the image used to sync the containers - default is bitnami/kubectl:latest - type: string - schedule: - description: Schedule is the the cron time string format, - see https://en.wikipedia.org/wiki/Cron. - type: string - type: object cacheZoneSize: anyOf: - type: integer diff --git a/config/crd/bases/extensions.tsuru.io_rpaasplans.yaml b/config/crd/bases/extensions.tsuru.io_rpaasplans.yaml index 198686f10..fa3bc2957 100644 --- a/config/crd/bases/extensions.tsuru.io_rpaasplans.yaml +++ b/config/crd/bases/extensions.tsuru.io_rpaasplans.yaml @@ -54,46 +54,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - cacheSnapshotEnabled: - type: boolean - cacheSnapshotStorage: - properties: - storageClassName: - type: string - storageSize: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - volumeLabels: - additionalProperties: - type: string - type: object - type: object - cacheSnapshotSync: - properties: - cmdPVCToPod: - description: CmdPVCToPod is used to customize command used - to sync persistent storage (PVC) to memory cache (POD) - items: - type: string - type: array - cmdPodToPVC: - description: CmdPodToPVC is used to customize command used - to sync memory cache (POD) to persistent storage (PVC) - items: - type: string - type: array - image: - description: Container is the image used to sync the containers - default is bitnami/kubectl:latest - type: string - schedule: - description: Schedule is the the cron time string format, - see https://en.wikipedia.org/wiki/Cron. - type: string - type: object cacheZoneSize: anyOf: - type: integer diff --git a/controllers/controller.go b/controllers/controller.go index bf46c252e..b015fbaaf 100644 --- a/controllers/controller.go +++ b/controllers/controller.go @@ -46,18 +46,7 @@ import ( ) const ( - defaultConfigHistoryLimit = 10 - defaultCacheSnapshotCronImage = "bitnami/kubectl:latest" - defaultCacheSnapshotSchedule = "* * * * *" - volumeTeamLabel = "tsuru.io/volume-team" - - cacheSnapshotCronJobSuffix = "-snapshot-cron-job" - cacheSnapshotVolumeSuffix = "-snapshot-volume" - - cacheSnapshotMountPoint = "/var/cache/cache-snapshot" - - rsyncCommandPodToPVC = "rsync -avz --recursive --delete --temp-dir=${CACHE_SNAPSHOT_MOUNTPOINT}/temp ${CACHE_PATH}/nginx ${CACHE_SNAPSHOT_MOUNTPOINT}" - rsyncCommandPVCToPod = "rsync -avz --recursive --delete --temp-dir=${CACHE_PATH}/nginx_tmp ${CACHE_SNAPSHOT_MOUNTPOINT}/nginx ${CACHE_PATH}" + defaultConfigHistoryLimit = 10 sessionTicketsSecretSuffix = "-session-tickets" sessionTicketsCronJobSuffix = "-session-tickets" @@ -69,30 +58,6 @@ const ( ) var ( - defaultCacheSnapshotCmdPodToPVC = []string{ - "/bin/bash", - "-c", - `pods=($(kubectl -n ${SERVICE_NAME} get pod -l rpaas.extensions.tsuru.io/service-name=${SERVICE_NAME} -l rpaas.extensions.tsuru.io/instance-name=${INSTANCE_NAME} --field-selector status.phase=Running -o=jsonpath='{.items[*].metadata.name}')); -for pod in ${pods[@]}; do - kubectl -n ${SERVICE_NAME} exec ${pod} -- ${POD_CMD}; - if [[ $? == 0 ]]; then - exit 0; - fi -done -echo "No pods found"; -exit 1 -`} - - defaultCacheSnapshotCmdPVCToPod = []string{ - "/bin/bash", - "-c", - ` -mkdir -p ${CACHE_SNAPSHOT_MOUNTPOINT}/temp; -mkdir -p ${CACHE_SNAPSHOT_MOUNTPOINT}/nginx; -mkdir -p ${CACHE_PATH}/nginx_tmp; -${POD_CMD} -`} - defaultRotateTLSSessionTicketsImage = "bitnami/kubectl:latest" sessionTicketsVolumeName = "tls-session-tickets" @@ -371,10 +336,11 @@ func newCronJobForSessionTickets(instance *v1alpha1.RpaasInstance) *batchv1beta1 rotationInterval = instance.Spec.TLSSessionResumption.SessionTicket.KeyRotationInterval } - image := defaultCacheSnapshotCronImage + image := defaultRotateTLSSessionTicketsImage if enabled && instance.Spec.TLSSessionResumption.SessionTicket.Image != "" { image = instance.Spec.TLSSessionResumption.SessionTicket.Image } + var jobsHistoryLimit int32 = 1 return &batchv1beta1.CronJob{ TypeMeta: metav1.TypeMeta{ @@ -746,141 +712,6 @@ func (r *RpaasInstanceReconciler) reconcileNginx(ctx context.Context, instance * return err } -func (r *RpaasInstanceReconciler) reconcileCacheSnapshot(ctx context.Context, instance *v1alpha1.RpaasInstance, plan *v1alpha1.RpaasPlan) error { - if plan.Spec.Config.CacheSnapshotEnabled { - err := r.reconcileCacheSnapshotCronJob(ctx, instance, plan) - if err != nil { - return err - } - return r.reconcileCacheSnapshotVolume(ctx, instance, plan) - } - - err := r.destroyCacheSnapshotCronJob(ctx, instance) - if err != nil { - return err - } - - return r.destroyCacheSnapshotVolume(ctx, instance) -} - -func (r *RpaasInstanceReconciler) reconcileCacheSnapshotCronJob(ctx context.Context, instance *v1alpha1.RpaasInstance, plan *v1alpha1.RpaasPlan) error { - foundCronJob := &batchv1beta1.CronJob{} - cronName := nameForCronJob(instance.Name + cacheSnapshotCronJobSuffix) - err := r.Client.Get(ctx, types.NamespacedName{Name: cronName, Namespace: instance.Namespace}, foundCronJob) - if err != nil && !k8sErrors.IsNotFound(err) { - return err - } - - newestCronJob := newCronJob(instance, plan) - if k8sErrors.IsNotFound(err) { - return r.Client.Create(ctx, newestCronJob) - } - - newestCronJob.ObjectMeta.ResourceVersion = foundCronJob.ObjectMeta.ResourceVersion - if !equality.Semantic.DeepDerivative(foundCronJob.Spec, newestCronJob.Spec) { - return r.Client.Update(ctx, newestCronJob) - } - - return nil -} - -func (r *RpaasInstanceReconciler) destroyCacheSnapshotCronJob(ctx context.Context, instance *v1alpha1.RpaasInstance) error { - cronName := nameForCronJob(instance.Name + cacheSnapshotCronJobSuffix) - cronJob := &batchv1beta1.CronJob{} - - err := r.Client.Get(ctx, types.NamespacedName{Name: cronName, Namespace: instance.Namespace}, cronJob) - isNotFound := k8sErrors.IsNotFound(err) - if err != nil && !isNotFound { - return err - } else if isNotFound { - return nil - } - - logrus.Infof("deleting cronjob %s", cronName) - return r.Client.Delete(ctx, cronJob) -} - -func (r *RpaasInstanceReconciler) reconcileCacheSnapshotVolume(ctx context.Context, instance *v1alpha1.RpaasInstance, plan *v1alpha1.RpaasPlan) error { - pvcName := instance.Name + cacheSnapshotVolumeSuffix - - pvc := &corev1.PersistentVolumeClaim{} - err := r.Client.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: instance.Namespace}, pvc) - isNotFound := k8sErrors.IsNotFound(err) - if err != nil && !isNotFound { - return err - } else if !isNotFound { - return nil - } - - cacheSnapshotStorage := plan.Spec.Config.CacheSnapshotStorage - volumeMode := corev1.PersistentVolumeFilesystem - labels := labelsForRpaasInstance(instance) - if teamOwner := instance.TeamOwner(); teamOwner != "" { - labels[volumeTeamLabel] = teamOwner - } - for k, v := range cacheSnapshotStorage.VolumeLabels { - labels[k] = v - } - - pvc = &corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ - Name: pvcName, - Namespace: instance.Namespace, - Labels: labels, - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(instance, schema.GroupVersionKind{ - Group: v1alpha1.GroupVersion.Group, - Version: v1alpha1.GroupVersion.Version, - Kind: "RpaasInstance", - }), - }, - }, - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "PersistentVolumeClaim", - }, - Spec: corev1.PersistentVolumeClaimSpec{ - AccessModes: []corev1.PersistentVolumeAccessMode{ - corev1.ReadWriteMany, - }, - VolumeMode: &volumeMode, - StorageClassName: cacheSnapshotStorage.StorageClassName, - }, - } - - storageSize := plan.Spec.Config.CacheSize - if cacheSnapshotStorage.StorageSize != nil && !cacheSnapshotStorage.StorageSize.IsZero() { - storageSize = cacheSnapshotStorage.StorageSize - } - - if storageSize != nil && !storageSize.IsZero() { - pvc.Spec.Resources = corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - "storage": *storageSize, - }, - } - } - - logrus.Infof("creating PersistentVolumeClaim %s", pvcName) - return r.Client.Create(ctx, pvc) -} - -func (r *RpaasInstanceReconciler) destroyCacheSnapshotVolume(ctx context.Context, instance *v1alpha1.RpaasInstance) error { - pvcName := instance.Name + cacheSnapshotVolumeSuffix - - pvc := &corev1.PersistentVolumeClaim{} - err := r.Client.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: instance.Namespace}, pvc) - isNotFound := k8sErrors.IsNotFound(err) - if err != nil && !isNotFound { - return err - } else if isNotFound { - return nil - } - - logrus.Infof("deleting PersistentVolumeClaim %s", pvcName) - return r.Client.Delete(ctx, pvc) -} - func (r *RpaasInstanceReconciler) renderTemplate(ctx context.Context, instance *v1alpha1.RpaasInstance, plan *v1alpha1.RpaasPlan) (string, error) { blocks, err := r.getConfigurationBlocks(ctx, instance, plan) if err != nil { @@ -1154,51 +985,6 @@ func newNginx(instanceMergedWithFlavors *v1alpha1.RpaasInstance, plan *v1alpha1. }) } - if !plan.Spec.Config.CacheSnapshotEnabled { - return n - } - - initCmd := defaultCacheSnapshotCmdPVCToPod - if len(plan.Spec.Config.CacheSnapshotSync.CmdPVCToPod) > 0 { - initCmd = plan.Spec.Config.CacheSnapshotSync.CmdPVCToPod - } - - n.Spec.PodTemplate.Volumes = append(n.Spec.PodTemplate.Volumes, corev1.Volume{ - Name: "cache-snapshot-volume", - VolumeSource: corev1.VolumeSource{ - PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ - ClaimName: instanceMergedWithFlavors.Name + cacheSnapshotVolumeSuffix, - }, - }, - }) - - cacheSnapshotVolume := corev1.VolumeMount{ - Name: "cache-snapshot-volume", - MountPath: cacheSnapshotMountPoint, - } - - n.Spec.PodTemplate.VolumeMounts = append(n.Spec.PodTemplate.VolumeMounts, cacheSnapshotVolume) - - n.Spec.PodTemplate.InitContainers = append(n.Spec.PodTemplate.InitContainers, corev1.Container{ - Name: "restore-snapshot", - Image: plan.Spec.Image, - Command: []string{ - initCmd[0], - }, - Args: initCmd[1:], - VolumeMounts: []corev1.VolumeMount{ - cacheSnapshotVolume, - { - Name: "cache-vol", - MountPath: plan.Spec.Config.CachePath, - }, - }, - Env: append(cacheSnapshotEnvVars(instanceMergedWithFlavors, plan), corev1.EnvVar{ - Name: "POD_CMD", - Value: interpolateCacheSnapshotPodCmdTemplate(rsyncCommandPVCToPod, plan), - }), - }) - return n } @@ -1287,82 +1073,6 @@ func newHPA(instance *v1alpha1.RpaasInstance, nginx *nginxv1alpha1.Nginx) autosc } } -func newCronJob(instance *v1alpha1.RpaasInstance, plan *v1alpha1.RpaasPlan) *batchv1beta1.CronJob { - cronName := nameForCronJob(instance.Name + cacheSnapshotCronJobSuffix) - - schedule := defaultCacheSnapshotSchedule - if plan.Spec.Config.CacheSnapshotSync.Schedule != "" { - schedule = plan.Spec.Config.CacheSnapshotSync.Schedule - } - - image := defaultCacheSnapshotCronImage - if plan.Spec.Config.CacheSnapshotSync.Image != "" { - image = plan.Spec.Config.CacheSnapshotSync.Image - } - - cmds := defaultCacheSnapshotCmdPodToPVC - if len(plan.Spec.Config.CacheSnapshotSync.CmdPodToPVC) > 0 { - cmds = plan.Spec.Config.CacheSnapshotSync.CmdPodToPVC - } - jobLabels := labelsForRpaasInstance(instance) - jobLabels["log-app-name"] = instance.Name - jobLabels["log-process-name"] = "cache-synchronize" - - var jobsHistoryLimit int32 = 1 - - return &batchv1beta1.CronJob{ - ObjectMeta: metav1.ObjectMeta{ - Name: cronName, - Namespace: instance.Namespace, - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(instance, schema.GroupVersionKind{ - Group: v1alpha1.GroupVersion.Group, - Version: v1alpha1.GroupVersion.Version, - Kind: "RpaasInstance", - }), - }, - Labels: labelsForRpaasInstance(instance), - }, - TypeMeta: metav1.TypeMeta{ - APIVersion: "batch/v1beta1", - Kind: "CronJob", - }, - Spec: batchv1beta1.CronJobSpec{ - Schedule: schedule, - ConcurrencyPolicy: batchv1beta1.ForbidConcurrent, - SuccessfulJobsHistoryLimit: &jobsHistoryLimit, - FailedJobsHistoryLimit: &jobsHistoryLimit, - JobTemplate: batchv1beta1.JobTemplateSpec{ - Spec: batchv1.JobSpec{ - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: jobLabels, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: "rpaas-cache-snapshot-cronjob", - Containers: []corev1.Container{ - { - Name: "cache-synchronize", - Image: image, - Command: []string{ - cmds[0], - }, - Args: cmds[1:], - Env: append(cacheSnapshotEnvVars(instance, plan), corev1.EnvVar{ - Name: "POD_CMD", - Value: interpolateCacheSnapshotPodCmdTemplate(rsyncCommandPodToPVC, plan), - }), - }, - }, - RestartPolicy: corev1.RestartPolicyNever, - }, - }, - }, - }, - }, - } -} - func minutesIntervalToSchedule(minutes uint32) string { oneMinute := uint32(1) if minutes <= oneMinute { @@ -1372,23 +1082,6 @@ func minutesIntervalToSchedule(minutes uint32) string { return fmt.Sprintf("*/%d * * * *", minutes) } -func interpolateCacheSnapshotPodCmdTemplate(podCmd string, plan *v1alpha1.RpaasPlan) string { - replacer := strings.NewReplacer( - "${CACHE_SNAPSHOT_MOUNTPOINT}", cacheSnapshotMountPoint, - "${CACHE_PATH}", plan.Spec.Config.CachePath, - ) - return replacer.Replace(podCmd) -} - -func cacheSnapshotEnvVars(instance *v1alpha1.RpaasInstance, plan *v1alpha1.RpaasPlan) []corev1.EnvVar { - return []corev1.EnvVar{ - {Name: "SERVICE_NAME", Value: instance.Namespace}, - {Name: "INSTANCE_NAME", Value: instance.Name}, - {Name: "CACHE_SNAPSHOT_MOUNTPOINT", Value: cacheSnapshotMountPoint}, - {Name: "CACHE_PATH", Value: plan.Spec.Config.CachePath}, - } -} - func shouldDeleteOldConfig(instance *v1alpha1.RpaasInstance, configList *corev1.ConfigMapList) bool { limit := defaultConfigHistoryLimit diff --git a/controllers/controller_test.go b/controllers/controller_test.go index 072328432..8939b41f7 100644 --- a/controllers/controller_test.go +++ b/controllers/controller_test.go @@ -1104,237 +1104,10 @@ func Test_reconcilePDB(t *testing.T) { } } -func Test_reconcileSnapshotVolume(t *testing.T) { - ctx := context.TODO() - rpaasInstance := newEmptyRpaasInstance() - rpaasInstance.Name = "my-instance" - rpaasInstance.SetTeamOwner("team-one") - - tests := []struct { - name string - planSpec v1alpha1.RpaasPlanSpec - assert func(*testing.T, *corev1.PersistentVolumeClaim) - }{ - { - name: "Should repass attributes to PVC", - planSpec: v1alpha1.RpaasPlanSpec{ - Config: v1alpha1.NginxConfig{ - CacheSize: resourceMustParsePtr("10Gi"), - CacheSnapshotStorage: v1alpha1.CacheSnapshotStorage{ - StorageClassName: strPtr("my-storage-class"), - }, - }, - }, - assert: func(t *testing.T, pvc *corev1.PersistentVolumeClaim) { - assert.Equal(t, pvc.ObjectMeta.OwnerReferences[0].Kind, "RpaasInstance") - assert.Equal(t, pvc.ObjectMeta.OwnerReferences[0].Name, rpaasInstance.Name) - assert.Equal(t, pvc.Spec.StorageClassName, strPtr("my-storage-class")) - assert.Equal(t, pvc.Spec.AccessModes, []corev1.PersistentVolumeAccessMode{corev1.ReadWriteMany}) - - parsedSize, _ := resource.ParseQuantity("10Gi") - assert.Equal(t, parsedSize, pvc.Spec.Resources.Requests["storage"]) - }, - }, - { - name: "Should repass volume labels to PVC", - planSpec: v1alpha1.RpaasPlanSpec{ - Config: v1alpha1.NginxConfig{ - CacheSnapshotStorage: v1alpha1.CacheSnapshotStorage{ - StorageClassName: strPtr("my-storage-class"), - VolumeLabels: map[string]string{ - "some-label": "foo", - "other-label": "bar", - }, - }, - }, - }, - assert: func(t *testing.T, pvc *corev1.PersistentVolumeClaim) { - assert.Equal(t, 5, len(pvc.ObjectMeta.Labels)) - assert.Equal(t, map[string]string{ - "some-label": "foo", - "other-label": "bar", - "tsuru.io/volume-team": "team-one", - "rpaas.extensions.tsuru.io/instance-name": "my-instance", - "rpaas.extensions.tsuru.io/plan-name": "my-plan", - }, pvc.ObjectMeta.Labels) - }, - }, - - { - name: "Should priorize the team inside plan", - planSpec: v1alpha1.RpaasPlanSpec{ - Config: v1alpha1.NginxConfig{ - CacheSnapshotStorage: v1alpha1.CacheSnapshotStorage{ - VolumeLabels: map[string]string{ - "tsuru.io/volume-team": "another-team", - }, - }, - }, - }, - assert: func(t *testing.T, pvc *corev1.PersistentVolumeClaim) { - assert.Equal(t, "another-team", pvc.ObjectMeta.Labels["tsuru.io/volume-team"]) - }, - }, - { - name: "Should allow to customize size of PVC separately of cache settings", - planSpec: v1alpha1.RpaasPlanSpec{ - Config: v1alpha1.NginxConfig{ - CacheSize: resourceMustParsePtr("10Gi"), - CacheSnapshotStorage: v1alpha1.CacheSnapshotStorage{ - StorageSize: resourceMustParsePtr("100Gi"), - }, - }, - }, - assert: func(t *testing.T, pvc *corev1.PersistentVolumeClaim) { - parsedSize, _ := resource.ParseQuantity("100Gi") - assert.Equal(t, parsedSize, pvc.Spec.Resources.Requests["storage"]) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - reconciler := newRpaasInstanceReconciler() - err := reconciler.reconcileCacheSnapshotVolume(ctx, rpaasInstance, &v1alpha1.RpaasPlan{Spec: tt.planSpec}) - require.NoError(t, err) - - pvc := &corev1.PersistentVolumeClaim{} - err = reconciler.Client.Get(ctx, types.NamespacedName{ - Name: rpaasInstance.Name + "-snapshot-volume", - Namespace: rpaasInstance.Namespace, - }, pvc) - require.NoError(t, err) - - tt.assert(t, pvc) - }) - } - -} - -func Test_destroySnapshotVolume(t *testing.T) { - ctx := context.TODO() - instance1 := newEmptyRpaasInstance() - instance1.Name = "instance-1" - - pvc := &corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ - Name: "instance-1-snapshot-volume", - Namespace: "default", - }, - } - reconciler := newRpaasInstanceReconciler(pvc) - - err := reconciler.destroyCacheSnapshotVolume(ctx, instance1) - require.NoError(t, err) - - pvc = &corev1.PersistentVolumeClaim{} - err = reconciler.Client.Get(context.TODO(), types.NamespacedName{Name: instance1.Name + "-snapshot-volume", Namespace: instance1.Namespace}, pvc) - require.True(t, k8sErrors.IsNotFound(err)) -} - -func Test_reconcileCacheSnapshotCronJobCreation(t *testing.T) { - ctx := context.TODO() - instance1 := newEmptyRpaasInstance() - instance1.Name = "instance-1" - - reconciler := newRpaasInstanceReconciler() - - plan := &v1alpha1.RpaasPlan{ - Spec: v1alpha1.RpaasPlanSpec{}, - } - - err := reconciler.reconcileCacheSnapshotCronJob(ctx, instance1, plan) - require.NoError(t, err) - - cronJob := &batchv1beta1.CronJob{} - err = reconciler.Client.Get(context.TODO(), types.NamespacedName{Name: instance1.Name + "-snapshot-cron-job", Namespace: instance1.Namespace}, cronJob) - require.NoError(t, err) - - assert.Equal(t, "RpaasInstance", cronJob.ObjectMeta.OwnerReferences[0].Kind) - assert.Equal(t, instance1.Name, cronJob.ObjectMeta.OwnerReferences[0].Name) - - assert.Equal(t, map[string]string{ - "rpaas.extensions.tsuru.io/instance-name": "instance-1", - "rpaas.extensions.tsuru.io/plan-name": "my-plan", - }, cronJob.ObjectMeta.Labels) - - assert.Equal(t, map[string]string{ - "log-app-name": "instance-1", - "log-process-name": "cache-synchronize", - "rpaas.extensions.tsuru.io/instance-name": "instance-1", - "rpaas.extensions.tsuru.io/plan-name": "my-plan", - }, cronJob.Spec.JobTemplate.Spec.Template.ObjectMeta.Labels) -} - -func Test_reconcileCacheSnapshotCronJobUpdate(t *testing.T) { - ctx := context.TODO() - instance1 := newEmptyRpaasInstance() - instance1.Name = "instance-1" - - previousCronJob := &batchv1beta1.CronJob{ - ObjectMeta: metav1.ObjectMeta{ - Name: instance1.Name + "-snapshot-cronjob", - }, - Spec: batchv1beta1.CronJobSpec{ - Schedule: "old-schedule", - }, - } - - reconciler := newRpaasInstanceReconciler(previousCronJob) - - plan := &v1alpha1.RpaasPlan{ - Spec: v1alpha1.RpaasPlanSpec{ - Config: v1alpha1.NginxConfig{ - CacheSnapshotSync: v1alpha1.CacheSnapshotSyncSpec{ - Schedule: "new-schedule", - }, - }, - }, - } - - err := reconciler.reconcileCacheSnapshotCronJob(ctx, instance1, plan) - require.NoError(t, err) - - cronJob := &batchv1beta1.CronJob{} - err = reconciler.Client.Get(context.TODO(), types.NamespacedName{Name: instance1.Name + "-snapshot-cron-job", Namespace: instance1.Namespace}, cronJob) - require.NoError(t, err) - - assert.Equal(t, "RpaasInstance", cronJob.ObjectMeta.OwnerReferences[0].Kind) - assert.Equal(t, instance1.Name, cronJob.ObjectMeta.OwnerReferences[0].Name) - assert.Equal(t, "new-schedule", cronJob.Spec.Schedule) -} - -func Test_destroySnapshotCronJob(t *testing.T) { - ctx := context.TODO() - instance1 := newEmptyRpaasInstance() - instance1.Name = "instance-1" - - cronJob := &batchv1beta1.CronJob{ - ObjectMeta: metav1.ObjectMeta{ - Name: instance1.Name + "-snapshot-cron-job", - Namespace: instance1.Namespace, - }, - } - - reconciler := newRpaasInstanceReconciler(cronJob) - - err := reconciler.destroyCacheSnapshotCronJob(ctx, instance1) - require.NoError(t, err) - - cronJob = &batchv1beta1.CronJob{} - - err = reconciler.Client.Get(context.TODO(), types.NamespacedName{Name: instance1.Name + "-snapshot-cron-job", Namespace: instance1.Namespace}, cronJob) - require.True(t, k8sErrors.IsNotFound(err)) -} - func int32Ptr(n int32) *int32 { return &n } -func strPtr(s string) *string { - return &s -} - func newEmptyRpaasInstance() *v1alpha1.RpaasInstance { return &v1alpha1.RpaasInstance{ TypeMeta: metav1.TypeMeta{ @@ -1365,130 +1138,6 @@ func newRpaasFlavor() *v1alpha1.RpaasFlavor { } } -func TestReconcile(t *testing.T) { - rpaas := &v1alpha1.RpaasInstance{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-instance", - Namespace: "default", - }, - Spec: v1alpha1.RpaasInstanceSpec{ - PlanName: "my-plan", - }, - } - plan := &v1alpha1.RpaasPlan{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-plan", - Namespace: "default", - }, - Spec: v1alpha1.RpaasPlanSpec{ - Image: "tsuru:mynginx:test", - Config: v1alpha1.NginxConfig{ - CacheEnabled: v1alpha1.Bool(true), - CacheSize: resourceMustParsePtr("100M"), - CacheSnapshotEnabled: true, - CacheSnapshotStorage: v1alpha1.CacheSnapshotStorage{ - StorageClassName: strPtr("my-storage-class"), - }, - CachePath: "/var/cache/nginx/rpaas", - CacheSnapshotSync: v1alpha1.CacheSnapshotSyncSpec{ - Schedule: "1 * * * *", - Image: "test/test:latest", - CmdPodToPVC: []string{ - "/bin/bash", - "-c", - "echo 'this is a test'", - }, - CmdPVCToPod: []string{ - "/bin/bash", - "-c", - "echo 'this is a the first pod sync'", - }, - }, - }, - }, - } - - defaultFlavor := newRpaasFlavor() - defaultFlavor.Name = "default" - defaultFlavor.Spec.Default = true - defaultFlavor.Spec.InstanceTemplate = &v1alpha1.RpaasInstanceSpec{ - DNS: &v1alpha1.DNSConfig{ - Zone: "test-zone", - TTL: func() *int32 { ttl := int32(25); return &ttl }(), - }, - Service: &nginxv1alpha1.NginxService{ - Annotations: map[string]string{ - "flavored-service-annotation": "v1", - }, - Labels: map[string]string{ - "flavored-service-label": "v1", - "conflict-label": "ignored", - }, - }, - } - reconciler := newRpaasInstanceReconciler(rpaas, plan, defaultFlavor) - result, err := reconciler.Reconcile(context.Background(), reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "default", Name: "my-instance"}}) - require.NoError(t, err) - - assert.Equal(t, result, reconcile.Result{}) - - nginx := &nginxv1alpha1.Nginx{} - err = reconciler.Client.Get(context.TODO(), types.NamespacedName{Name: rpaas.Name, Namespace: rpaas.Namespace}, nginx) - require.NoError(t, err) - assert.Equal(t, "cache-snapshot-volume", nginx.Spec.PodTemplate.Volumes[0].Name) - assert.Equal(t, &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "my-instance-snapshot-volume"}, nginx.Spec.PodTemplate.Volumes[0].PersistentVolumeClaim) - assert.Equal(t, "cache-snapshot-volume", nginx.Spec.PodTemplate.VolumeMounts[0].Name) - assert.Equal(t, "/var/cache/cache-snapshot", nginx.Spec.PodTemplate.VolumeMounts[0].MountPath) - assert.Equal(t, nginx.Spec.PodTemplate.Ports, []corev1.ContainerPort{ - {Name: "nginx-metrics", ContainerPort: 8800, Protocol: "TCP"}, - }) - assert.Equal(t, resource.MustParse("100M"), *nginx.Spec.Cache.Size) - assert.Equal(t, corev1.ServiceTypeLoadBalancer, nginx.Spec.Service.Type) - assert.Equal(t, "my-instance.test-zone", nginx.Spec.Service.Annotations[externalDNSHostnameLabel]) - assert.Equal(t, "25", nginx.Spec.Service.Annotations[externalDNSTTLLabel]) - - initContainer := nginx.Spec.PodTemplate.InitContainers[0] - assert.Equal(t, "restore-snapshot", initContainer.Name) - assert.Equal(t, "tsuru:mynginx:test", initContainer.Image) - assert.Equal(t, "/bin/bash", initContainer.Command[0]) - assert.Equal(t, "-c", initContainer.Args[0]) - assert.Equal(t, "echo 'this is a the first pod sync'", initContainer.Args[1]) - assert.Equal(t, []corev1.EnvVar{ - {Name: "SERVICE_NAME", Value: "default"}, - {Name: "INSTANCE_NAME", Value: "my-instance"}, - {Name: "CACHE_SNAPSHOT_MOUNTPOINT", Value: "/var/cache/cache-snapshot"}, - {Name: "CACHE_PATH", Value: "/var/cache/nginx/rpaas"}, - {Name: "POD_CMD", Value: "rsync -avz --recursive --delete --temp-dir=/var/cache/nginx/rpaas/nginx_tmp /var/cache/cache-snapshot/nginx /var/cache/nginx/rpaas"}, - }, initContainer.Env) - - assert.Equal(t, []corev1.VolumeMount{ - {Name: "cache-snapshot-volume", MountPath: "/var/cache/cache-snapshot"}, - {Name: "cache-vol", MountPath: "/var/cache/nginx/rpaas"}, - }, initContainer.VolumeMounts) - - cronJob := &batchv1beta1.CronJob{} - err = reconciler.Client.Get(context.TODO(), types.NamespacedName{Name: "my-instance-snapshot-cron-job", Namespace: rpaas.Namespace}, cronJob) - require.NoError(t, err) - - assert.Equal(t, "1 * * * *", cronJob.Spec.Schedule) - podTemplateSpec := cronJob.Spec.JobTemplate.Spec.Template - podSpec := podTemplateSpec.Spec - assert.Equal(t, "test/test:latest", podSpec.Containers[0].Image) - assert.Equal(t, "/bin/bash", podSpec.Containers[0].Command[0]) - assert.Equal(t, "-c", podSpec.Containers[0].Args[0]) - assert.Equal(t, "echo 'this is a test'", podSpec.Containers[0].Args[1]) - assert.Equal(t, "my-instance", podTemplateSpec.ObjectMeta.Labels["log-app-name"]) - assert.Equal(t, "cache-synchronize", podTemplateSpec.ObjectMeta.Labels["log-process-name"]) - assert.Equal(t, []corev1.EnvVar{ - {Name: "SERVICE_NAME", Value: "default"}, - {Name: "INSTANCE_NAME", Value: "my-instance"}, - {Name: "CACHE_SNAPSHOT_MOUNTPOINT", Value: "/var/cache/cache-snapshot"}, - {Name: "CACHE_PATH", Value: "/var/cache/nginx/rpaas"}, - {Name: "POD_CMD", Value: "rsync -avz --recursive --delete --temp-dir=/var/cache/cache-snapshot/temp /var/cache/nginx/rpaas/nginx /var/cache/cache-snapshot"}, - }, podSpec.Containers[0].Env) - -} - func TestReconcileWithProxyProtocol(t *testing.T) { rpaas := &v1alpha1.RpaasInstance{ ObjectMeta: metav1.ObjectMeta{ diff --git a/controllers/rpaasinstance_controller.go b/controllers/rpaasinstance_controller.go index bc5a09258..5984b22d1 100644 --- a/controllers/rpaasinstance_controller.go +++ b/controllers/rpaasinstance_controller.go @@ -158,10 +158,6 @@ func (r *RpaasInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Reques return ctrl.Result{}, err } - if err = r.reconcileCacheSnapshot(ctx, instanceMergedWithFlavors, plan); err != nil { - return ctrl.Result{}, err - } - if err = r.reconcileHPA(ctx, instanceMergedWithFlavors, nginx); err != nil { return ctrl.Result{}, err }