diff --git a/hack/shoot-comparator/cmd/comparator/directories.go b/hack/shoot-comparator/cmd/comparator/directories.go index 41e9a138..15f3f407 100644 --- a/hack/shoot-comparator/cmd/comparator/directories.go +++ b/hack/shoot-comparator/cmd/comparator/directories.go @@ -51,7 +51,7 @@ var directoriesCmd = &cobra.Command{ } slog.Info(fmt.Sprintf("Comparing directories: %s and %s", leftDir, rightDir)) - result, err := directories.CompareDirectories(leftDir, rightDir, time.Time{}) + result, err := directories.CompareDirectories(leftDir, rightDir, fromDate) if err != nil { slog.Error(fmt.Sprintf("Failed to compare directories: %q", err.Error())) return diff --git a/hack/shoot-comparator/internal/directories/comparator.go b/hack/shoot-comparator/internal/directories/comparator.go index 8af19105..46e0e32b 100644 --- a/hack/shoot-comparator/internal/directories/comparator.go +++ b/hack/shoot-comparator/internal/directories/comparator.go @@ -1,12 +1,16 @@ package directories import ( + "io" "os" "path" "slices" + "strings" "time" + gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1" "github.com/kyma-project/infrastructure-manager/tools/shoot-comparator/internal/files" + "sigs.k8s.io/yaml" ) type Result struct { @@ -72,12 +76,12 @@ func getFileNames(dir string, olderThan time.Time) ([]string, error) { continue } - fileInfo, err := dirEntry.Info() + timestamp, err := getCreationDate(dirEntry, dir) if err != nil { return nil, err } - if fileInfo.ModTime().After(olderThan) { + if timestamp.After(olderThan) { fileNames = append(fileNames, dirEntry.Name()) } } @@ -87,6 +91,55 @@ func getFileNames(dir string, olderThan time.Time) ([]string, error) { return fileNames, nil } +func getCreationDate(entry os.DirEntry, dir string) (time.Time, error) { + filePath := path.Join(dir, entry.Name()) + + if strings.Contains(filePath, "shootCR") { + timestamp, err := getCreationDateFromYaml(filePath) + if err == nil { + return timestamp, nil + } + // getting modification time from entry is a fallback + } + + fileInfo, err := entry.Info() + if err != nil { + return time.Time{}, err + } + + return fileInfo.ModTime(), nil +} + +func getCreationDateFromYaml(filePath string) (time.Time, error) { + var shoot gardener.Shoot + + file, err := os.Open(filePath) + if err != nil { + return time.Time{}, err + } + + defer func() { + _ = file.Close() + }() + + bytes, err := io.ReadAll(file) + if err != nil { + return time.Time{}, err + } + + err = yaml.Unmarshal(bytes, &shoot) + if err != nil { + return time.Time{}, err + } + + if shoot.ObjectMeta.CreationTimestamp.Time.IsZero() { + //In case the file does not contain creation timestamp, we use current time as a fallback to include it in the comparison + return time.Now(), nil + } + + return shoot.ObjectMeta.CreationTimestamp.Time, nil +} + func getIntersection(leftFiles []string, rightFiles []string) []string { var intersection []string for _, leftFile := range leftFiles { diff --git a/hack/shoot-comparator/scripts/README.md b/hack/shoot-comparator/scripts/README.md index 1232b561..4020a340 100644 --- a/hack/shoot-comparator/scripts/README.md +++ b/hack/shoot-comparator/scripts/README.md @@ -124,3 +124,46 @@ In order to fetch the compared files you must copy the contents of the files. Yo ```bash ./fetch_shoots_for_provisioner_and_kim.sh ``` +## Cleaning volume with shoots, and mutations for Provisioner + +If you need to remove some files from the volume perform the following steps: +1. Check what node Provisioner is running on: +```bash +kubectl get po/ -n kcp-system -ojsonpath={.spec.nodeName} +``` +2. Modify the `./manifests/mount-prov-volume-with-write-access.yaml` file by providing the node name in the `nodeName` field. +3. Apply the changes by executing the following command: +```bash +kubectl apply -f ./manifests/mount-prov-volume-with-write-access.yaml +``` +4. Wait for the job to complete. Once the job is completed, exec into pod with the following command: +```bash +kubectl exec mount-prov-volume-with-write-access -n kcp-system -it -- /bin/sh +``` +5. Remove the files from the `/testdata/provisioner` directory. +6. Remove the pod with the following command: +```bash +kubectl delete -f ./manifests/mount-prov-volume-with-write-access.yaml +``` + +## Cleaning volume with shoots, and runtime CRs for KIM + +If you need to remove some files from the volume perform the following steps: +1. Check what node KIM is running on: +```bash +kubectl get po/ -n kcp-system -ojsonpath={.spec.nodeName} +``` +2. Modify the `./manifests/mount-kim-volume-with-write-access.yaml` file by providing the node name in the `nodeName` field. +3. Apply the changes by executing the following command: +```bash +kubectl apply -f ./manifests/mount-kim-volume-with-write-access.yaml +``` +4. Wait for the job to complete. Once the job is completed, exec into pod with the following command: +```bash +kubectl exec mount-kim-volume-with-write-access -n kcp-system -it -- /bin/sh +``` +5. Remove the files from the `/testdata/kim` directory. +6. Remove the pod with the following command: +```bash +kubectl delete -f ./manifests/mount-kim-volume-with-write-access.yaml +``` \ No newline at end of file diff --git a/hack/shoot-comparator/scripts/manifests/job.yaml b/hack/shoot-comparator/scripts/manifests/job.yaml index 32a23102..4e0ba739 100644 --- a/hack/shoot-comparator/scripts/manifests/job.yaml +++ b/hack/shoot-comparator/scripts/manifests/job.yaml @@ -45,9 +45,9 @@ spec: - --outputDir - /results # You can specify a date when the comparison should start from. The date should be in RFC3339 format. -# - --fromDate -# - 2024-07-31T20:04:29Z - image: europe-docker.pkg.dev/kyma-project/dev/shoot-comparator:PR-329 + - --fromDate + - 2024-09-19T00:00:00Z + image: europe-docker.pkg.dev/kyma-project/prod/shoot-comparator:v20240919-26f83162 name: compare-shoots resources: {} securityContext: diff --git a/hack/shoot-comparator/scripts/manifests/mount-kim-volume-with-write-access.yaml b/hack/shoot-comparator/scripts/manifests/mount-kim-volume-with-write-access.yaml new file mode 100644 index 00000000..6ac929bd --- /dev/null +++ b/hack/shoot-comparator/scripts/manifests/mount-kim-volume-with-write-access.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + labels: + run: mount-kim-volume-with-write-access + name: mount-kim-volume-with-write-access + namespace: kcp-system +spec: + nodeName: "KIM'S NODE NAME GOES HERE" + volumes: + - name: provisioner-kim + persistentVolumeClaim: + claimName: test-kim-shoot-spec-storage + containers: + - args: + - /bin/sh + - -c + - while true; do date; sleep 3; done + image: europe-docker.pkg.dev/kyma-project/prod/external/busybox:1.34.1-v1 + name: get-pvc + volumeMounts: + - name: provisioner-kim + mountPath: /testdata/kim + resources: {} + dnsPolicy: ClusterFirst + restartPolicy: Always \ No newline at end of file diff --git a/hack/shoot-comparator/scripts/manifests/mount-prov-volume-with-write-access.yaml b/hack/shoot-comparator/scripts/manifests/mount-prov-volume-with-write-access.yaml new file mode 100644 index 00000000..239355d6 --- /dev/null +++ b/hack/shoot-comparator/scripts/manifests/mount-prov-volume-with-write-access.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + labels: + run: mount-prov-volume-with-write-access + name: mount-prov-volume-with-write-access + namespace: kcp-system +spec: + nodeName: "PROVISIONER'S NODE NAME GOES HERE" + volumes: + - name: provisioner-ps + persistentVolumeClaim: + claimName: test-prov-shoot-spec-storage + containers: + - args: + - /bin/sh + - -c + - while true; do date; sleep 3; done + image: europe-docker.pkg.dev/kyma-project/prod/external/busybox:1.34.1-v1 + name: get-pvc + volumeMounts: + - name: provisioner-ps + mountPath: /testdata/provisioner + resources: {} + dnsPolicy: ClusterFirst + restartPolicy: Always \ No newline at end of file diff --git a/internal/controller/runtime/fsm/runtime_fsm_persist_shoot.go b/internal/controller/runtime/fsm/runtime_fsm_persist_shoot.go index afef364b..f5ac9a27 100644 --- a/internal/controller/runtime/fsm/runtime_fsm_persist_shoot.go +++ b/internal/controller/runtime/fsm/runtime_fsm_persist_shoot.go @@ -5,7 +5,9 @@ import ( "fmt" "io" "os" + "time" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/yaml" ) @@ -45,6 +47,10 @@ func sFnDumpShootSpec(_ context.Context, m *fsm, s *systemState) (stateFn, *ctrl return updateStatusAndStopWithError(err) } + convertedShoot.ObjectMeta.CreationTimestamp = metav1.Time{ + Time: time.Now(), + } + runtimeCp := s.instance.DeepCopy() if err := persist(paths["shoot"], convertedShoot, m.writerProvider); err != nil { diff --git a/internal/controller/runtime/fsm/runtime_fsm_persist_shoot_test.go b/internal/controller/runtime/fsm/runtime_fsm_persist_shoot_test.go index aa15d5f7..5fee081d 100644 --- a/internal/controller/runtime/fsm/runtime_fsm_persist_shoot_test.go +++ b/internal/controller/runtime/fsm/runtime_fsm_persist_shoot_test.go @@ -6,6 +6,7 @@ import ( "io" "time" + gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1" "github.com/kyma-project/infrastructure-manager/internal/controller/runtime/fsm/testing" "github.com/kyma-project/infrastructure-manager/internal/gardener/shoot" . "github.com/onsi/ginkgo/v2" //nolint:revive @@ -28,22 +29,15 @@ var _ = Describe("KIM sFnPersist", func() { expectedRuntime := testing.RuntimeOnlyName.DeepCopy() expectedRuntime.Spec.Shoot.Provider.Type = "aws" - expectedShoot, err := convertShoot(expectedRuntime, shoot.ConverterConfig{}) - Expect(err).To(BeNil()) - - shootWrite, err := yaml.Marshal(&expectedShoot) - Expect(err).To(BeNil()) - - runtimeWrite, err := yaml.Marshal(expectedRuntime) - Expect(err).To(BeNil()) - - expectedData := append(shootWrite, runtimeWrite...) - Expect(err).ShouldNot(HaveOccurred()) - It("should persist shoot data", func() { next, _, err := sFnDumpShootSpec(testCtx, must(newFakeFSM, withStorageWriter(testWriterGetter), withConverterConfig(shoot.ConverterConfig{})), &systemState{shoot: &testing.ShootNoDNS, instance: *expectedRuntime}) Expect(err).To(BeNil()) Expect(next).To(haveName("sFnUpdateStatus")) - Expect(b.Bytes()).To(Equal(expectedData)) + + var shootStored gardener.Shoot + + err = yaml.Unmarshal(b.Bytes(), &shootStored) + Expect(err).To(BeNil()) + Expect(shootStored.ObjectMeta.CreationTimestamp).To(Not(Equal(time.Time{}))) }) })