From 536fd77426e46a0ca1fd69d7f8f806551c5d274b Mon Sep 17 00:00:00 2001 From: Gerrit Date: Fri, 25 Aug 2023 18:25:27 +0200 Subject: [PATCH] Add postgres skeleton. --- deploy/postgres-local.yaml | 155 ++++++++++---- integration/postgres_test.go | 388 ++++++++++++++++++++++++++++++++++ integration/rethinkdb_test.go | 3 +- 3 files changed, 501 insertions(+), 45 deletions(-) create mode 100644 integration/postgres_test.go diff --git a/deploy/postgres-local.yaml b/deploy/postgres-local.yaml index 0a5e0bc..83067c2 100644 --- a/deploy/postgres-local.yaml +++ b/deploy/postgres-local.yaml @@ -1,29 +1,28 @@ +# DO NOT EDIT! This is auto-generated by the integration tests --- apiVersion: apps/v1 kind: StatefulSet metadata: + creationTimestamp: null labels: app: postgres name: postgres spec: - serviceName: postgres replicas: 1 selector: matchLabels: app: postgres + serviceName: postgres template: metadata: + creationTimestamp: null labels: app: postgres spec: containers: - - image: postgres:12-alpine - name: postgres - command: + - command: - backup-restore-sidecar - wait - ports: - - containerPort: 5432 env: - name: POSTGRES_DB valueFrom: @@ -45,17 +44,54 @@ spec: secretKeyRef: key: POSTGRES_DATA name: postgres + image: postgres:15-alpine + livenessProbe: + exec: + command: + - /bin/sh + - -c + - exec + - pg_isready + - -U + - test + - -h + - 127.0.0.1 + - -p + - "5432" + failureThreshold: 6 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: postgres + ports: + - containerPort: 5432 + readinessProbe: + exec: + command: + - /bin/sh + - -c + - exec + - pg_isready + - -U + - test + - -h + - 127.0.0.1 + - -p + - "5432" + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + resources: {} volumeMounts: - - name: postgres - mountPath: /data - - name: bin-provision + - mountPath: /data + name: data + - mountPath: /usr/local/bin/backup-restore-sidecar + name: bin-provision subPath: backup-restore-sidecar - mountPath: /usr/local/bin/backup-restore-sidecar - - name: backup-restore-sidecar-config - mountPath: /etc/backup-restore-sidecar - - image: postgres:12-alpine - name: backup-restore-sidecar - command: + - mountPath: /etc/backup-restore-sidecar + name: backup-restore-sidecar-config + - command: - backup-restore-sidecar - start - --log-level=debug @@ -70,52 +106,77 @@ spec: secretKeyRef: key: POSTGRES_USER name: postgres + image: postgres:15-alpine + name: backup-restore-sidecar + ports: + - containerPort: 8000 + name: grpc + resources: {} volumeMounts: - - name: postgres - mountPath: /data - - name: bin-provision + - mountPath: /backup + name: backup + - mountPath: /data + name: data + - mountPath: /etc/backup-restore-sidecar + name: backup-restore-sidecar-config + - mountPath: /usr/local/bin/backup-restore-sidecar + name: bin-provision subPath: backup-restore-sidecar - mountPath: /usr/local/bin/backup-restore-sidecar - - name: backup-restore-sidecar-config - mountPath: /etc/backup-restore-sidecar initContainers: - - name: backup-restore-sidecar-provider - image: ghcr.io/metal-stack/backup-restore-sidecar:latest - imagePullPolicy: IfNotPresent - command: + - command: - cp - /backup-restore-sidecar - /bin-provision - ports: - - containerPort: 2112 + image: ghcr.io/metal-stack/backup-restore-sidecar:latest + imagePullPolicy: IfNotPresent + name: backup-restore-sidecar-provider + resources: {} volumeMounts: - - name: bin-provision - mountPath: /bin-provision + - mountPath: /bin-provision + name: bin-provision volumes: - - name: postgres + - name: data + persistentVolumeClaim: + claimName: data + - name: backup persistentVolumeClaim: - claimName: postgres - - name: backup-restore-sidecar-config - configMap: + claimName: backup + - configMap: name: backup-restore-sidecar-config-postgres - - name: bin-provision - emptyDir: {} + name: backup-restore-sidecar-config + - emptyDir: {} + name: bin-provision + updateStrategy: {} volumeClaimTemplates: - metadata: - name: postgres + creationTimestamp: null + name: data spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi + status: {} + - metadata: + creationTimestamp: null + name: backup + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + status: {} +status: + availableReplicas: 0 + replicas: 0 --- apiVersion: v1 -kind: ConfigMap -metadata: - name: backup-restore-sidecar-config-postgres data: config.yaml: | + --- + bind-addr: 0.0.0.0 db: postgres db-data-directory: /data/postgres/ backup-provider: local @@ -123,21 +184,27 @@ data: object-prefix: postgres-test compression-method: tar post-exec-cmds: - - docker-entrypoint.sh postgres + - docker-entrypoint.sh postgres +kind: ConfigMap +metadata: + creationTimestamp: null + name: backup-restore-sidecar-config-postgres --- apiVersion: v1 kind: Secret metadata: + creationTimestamp: null name: postgres stringData: + POSTGRES_DATA: /data/postgres/ POSTGRES_DB: postgres - POSTGRES_USER: test POSTGRES_PASSWORD: test123! - POSTGRES_DATA: /data/postgres/ + POSTGRES_USER: test --- apiVersion: v1 kind: Service metadata: + creationTimestamp: null labels: app: postgres name: postgres @@ -146,8 +213,10 @@ spec: - name: "5432" port: 5432 targetPort: 5432 - - name: "metrics" + - name: metrics port: 2112 targetPort: 2112 selector: app: postgres +status: + loadBalancer: {} diff --git a/integration/postgres_test.go b/integration/postgres_test.go new file mode 100644 index 0000000..e71bed2 --- /dev/null +++ b/integration/postgres_test.go @@ -0,0 +1,388 @@ +package integration_test + +import ( + "context" + "testing" + + "github.com/metal-stack/backup-restore-sidecar/pkg/constants" + "github.com/metal-stack/metal-lib/pkg/pointer" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + postgresContainerImage = "postgres:15-alpine" +) + +func Test_Postgres(t *testing.T) { + const ( + db = "postgres" + postgresPassword = "test123!" + postgresUser = "test" + table = "precioustestdata" + ) + + var ( + sts = func(namespace string) *appsv1.StatefulSet { + return &appsv1.StatefulSet{ + TypeMeta: metav1.TypeMeta{ + Kind: "StatefulSet", + APIVersion: appsv1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "postgres", + Namespace: namespace, + Labels: map[string]string{ + "app": "postgres", + }, + }, + Spec: appsv1.StatefulSetSpec{ + ServiceName: "postgres", + Replicas: pointer.Pointer(int32(1)), + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "postgres", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "postgres", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + Containers: []corev1.Container{ + { + Name: "postgres", + Image: postgresContainerImage, + Command: []string{"backup-restore-sidecar", "wait"}, + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ + Command: []string{"/bin/sh", "-c", "exec", "pg_isready", "-U", postgresUser, "-h", "127.0.0.1", "-p", "5432"}, + }, + }, + InitialDelaySeconds: 30, + TimeoutSeconds: 5, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 6, + }, + ReadinessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ + Command: []string{"/bin/sh", "-c", "exec", "pg_isready", "-U", postgresUser, "-h", "127.0.0.1", "-p", "5432"}, + }, + }, + InitialDelaySeconds: 10, + TimeoutSeconds: 5, + PeriodSeconds: 10, + }, + Env: []corev1.EnvVar{ + { + Name: "POSTGRES_DB", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "postgres", + }, + Key: "POSTGRES_DB", + }, + }, + }, + { + Name: "POSTGRES_USER", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "postgres", + }, + Key: "POSTGRES_USER", + }, + }, + }, + { + Name: "POSTGRES_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "postgres", + }, + Key: "POSTGRES_PASSWORD", + }, + }, + }, + { + Name: "PGDATA", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "postgres", + }, + Key: "POSTGRES_DATA", + }, + }, + }, + }, + Ports: []corev1.ContainerPort{ + { + ContainerPort: 5432, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "data", + MountPath: "/data", + }, + { + Name: "bin-provision", + SubPath: "backup-restore-sidecar", + MountPath: "/usr/local/bin/backup-restore-sidecar", + }, + { + Name: "backup-restore-sidecar-config", + MountPath: "/etc/backup-restore-sidecar", + }, + }, + }, + { + Name: "backup-restore-sidecar", + Image: postgresContainerImage, + Command: []string{"backup-restore-sidecar", "start", "--log-level=debug"}, + Env: []corev1.EnvVar{ + { + Name: "BACKUP_RESTORE_SIDECAR_POSTGRES_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "postgres", + }, + Key: "POSTGRES_PASSWORD", + }, + }, + }, + { + Name: "BACKUP_RESTORE_SIDECAR_POSTGRES_USER", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "postgres", + }, + Key: "POSTGRES_USER", + }, + }, + }, + }, + Ports: []corev1.ContainerPort{ + { + Name: "grpc", + ContainerPort: 8000, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "backup", + MountPath: constants.SidecarBaseDir, + }, + { + Name: "data", + MountPath: "/data", + }, + { + Name: "backup-restore-sidecar-config", + MountPath: "/etc/backup-restore-sidecar", + }, + { + Name: "bin-provision", + SubPath: "backup-restore-sidecar", + MountPath: "/usr/local/bin/backup-restore-sidecar", + }, + }, + }, + }, + InitContainers: []corev1.Container{ + { + Name: "backup-restore-sidecar-provider", + Image: backupRestoreSidecarContainerImage, + ImagePullPolicy: corev1.PullIfNotPresent, + Command: []string{ + "cp", + "/backup-restore-sidecar", + "/bin-provision", + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "bin-provision", + MountPath: "/bin-provision", + }, + }, + }, + }, + Volumes: []corev1.Volume{ + { + Name: "data", + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: "data", + }, + }, + }, + { + Name: "backup", + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: "backup", + }, + }, + }, + { + Name: "backup-restore-sidecar-config", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "backup-restore-sidecar-config-postgres", + }, + }, + }, + }, + { + Name: "bin-provision", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + }, + }, + }, + VolumeClaimTemplates: []corev1.PersistentVolumeClaim{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "data", + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{ + corev1.ReadWriteOnce, + }, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), + }, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "backup", + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{ + corev1.ReadWriteOnce, + }, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), + }, + }, + }, + }, + }, + }, + } + } + + backingResources = func(namespace string) []client.Object { + return []client.Object{ + &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: corev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "backup-restore-sidecar-config-postgres", + Namespace: namespace, + }, + Data: map[string]string{ + "config.yaml": `--- +bind-addr: 0.0.0.0 +db: postgres +db-data-directory: /data/postgres/ +backup-provider: local +backup-cron-schedule: "*/1 * * * *" +object-prefix: postgres-test +compression-method: tar +post-exec-cmds: +- docker-entrypoint.sh postgres +`, + }, + }, + &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: corev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "postgres", + Namespace: namespace, + }, + StringData: map[string]string{ + "POSTGRES_DB": db, + "POSTGRES_USER": postgresUser, + "POSTGRES_PASSWORD": postgresPassword, + "POSTGRES_DATA": "/data/postgres/", + }, + }, + &corev1.Service{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: corev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "postgres", + Namespace: namespace, + Labels: map[string]string{ + "app": "postgres", + }, + }, + Spec: corev1.ServiceSpec{ + Selector: map[string]string{ + "app": "postgres", + }, + Ports: []corev1.ServicePort{ + { + Name: "5432", + Port: 5432, + TargetPort: intstr.FromInt32(5432), + }, + { + Name: "metrics", + Port: 2112, + TargetPort: intstr.FromInt32(2112), + }, + }, + }, + }, + } + } + + addTestData = func(t *testing.T, ctx context.Context) { + // TODO: Implement + } + + verifyTestData = func(t *testing.T, ctx context.Context) { + // TODO: Implement + } + ) + + restoreFlow(t, &flowSpec{ + databaseType: "postgres", + sts: sts, + backingResources: backingResources, + addTestData: addTestData, + verifyTestData: verifyTestData, + }) +} diff --git a/integration/rethinkdb_test.go b/integration/rethinkdb_test.go index d4ba933..7c35d6f 100644 --- a/integration/rethinkdb_test.go +++ b/integration/rethinkdb_test.go @@ -34,7 +34,6 @@ func Test_RethinkDB(t *testing.T) { rethinkdbPassword = "test123!" db = "backup-restore" table = "precioustestdata" - rethinkdbPodName = "rethinkdb-0" ) var ( @@ -408,7 +407,7 @@ post-exec-cmds: ) restoreFlow(t, &flowSpec{ - databaseType: db, + databaseType: "rethinkdb", sts: sts, backingResources: backingResources, addTestData: addTestData,