From 0b3cf60d0643f66a17ffcd97836d37ea85da2fa8 Mon Sep 17 00:00:00 2001 From: Fabian Fischer Date: Wed, 3 May 2023 10:34:01 +0200 Subject: [PATCH] Add UpdateStrategy to VSHNPostgreSQL --- functions/vshn-postgres-func/restart.go | 143 +++++++++ functions/vshn-postgres-func/restart_test.go | 92 ++++++ go.mod | 4 +- go.sum | 9 +- main.go | 17 +- .../restart/01-NoPendingReboot.yaml | 195 ++++++++++++ .../restart/02-PendingReboot.yaml | 191 ++++++++++++ .../restart/02-PendingRebootNoRestart.yaml | 195 ++++++++++++ .../restart/03-KeepRecentReboots.yaml | 291 ++++++++++++++++++ 9 files changed, 1128 insertions(+), 9 deletions(-) create mode 100644 functions/vshn-postgres-func/restart.go create mode 100644 functions/vshn-postgres-func/restart_test.go create mode 100644 test/transforms/vshn-postgres/restart/01-NoPendingReboot.yaml create mode 100644 test/transforms/vshn-postgres/restart/02-PendingReboot.yaml create mode 100644 test/transforms/vshn-postgres/restart/02-PendingRebootNoRestart.yaml create mode 100644 test/transforms/vshn-postgres/restart/03-KeepRecentReboots.yaml diff --git a/functions/vshn-postgres-func/restart.go b/functions/vshn-postgres-func/restart.go new file mode 100644 index 0000000..65d24aa --- /dev/null +++ b/functions/vshn-postgres-func/restart.go @@ -0,0 +1,143 @@ +package vshnpostgres + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + sgv1 "github.com/vshn/appcat-comp-functions/apis/stackgres/v1" + "github.com/vshn/appcat-comp-functions/runtime" + vshnv1 "github.com/vshn/component-appcat/apis/vshn/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + controllerruntime "sigs.k8s.io/controller-runtime" +) + +var sgDbOpsRestartRetention time.Duration = 30 * 24 * time.Hour + +// TransformRestart triggers a restart of the postgreqsql instance if there is a pending restart and the composite is configured to restart on update. +func TransformRestart(ctx context.Context, iof *runtime.Runtime) runtime.Result { + return transformRestart(ctx, iof, time.Now) +} + +func transformRestart(ctx context.Context, iof *runtime.Runtime, now func() time.Time) runtime.Result { + comp := vshnv1.VSHNPostgreSQL{} + err := iof.Desired.GetComposite(ctx, &comp) + if err != nil { + return runtime.NewFatal(ctx, err.Error()) + } + err = keepRecentRestartOps(ctx, iof, comp.GetName(), now) + if err != nil { + return runtime.NewFatal(ctx, err.Error()) + } + + if comp.Spec.Parameters.UpdateStrategy.Type == vshnv1.VSHNPostgreSQLUpdateStrategyTypeOnRestart { + return runtime.NewNormal() + } + + restartTime, err := getPendingRestart(ctx, iof) + if err != nil { + return runtime.NewWarning(ctx, err.Error()) + } + + if restartTime.IsZero() { + return runtime.NewNormal() + } + + err = scheduleRestart(ctx, iof, comp.GetName(), restartTime) + if err != nil { + return runtime.NewFatal(ctx, err.Error()) + } + + return runtime.NewNormal() +} + +func getPendingRestart(ctx context.Context, iof *runtime.Runtime) (time.Time, error) { + cluster := sgv1.SGCluster{} + + err := iof.Observed.GetFromObject(ctx, &cluster, "cluster") + if err != nil { + return time.Time{}, err + } + + log := controllerruntime.LoggerFrom(ctx).WithValues("cluster", cluster.Name) + if cluster.Status.Conditions == nil { + return time.Time{}, nil + } + + for _, cond := range *cluster.Status.Conditions { + if cond.Type == nil || *cond.Type != sgv1.SGClusterConditionTypePendingRestart || cond.Status == nil || cond.LastTransitionTime == nil { + continue + } + status, err := strconv.ParseBool(*cond.Status) + if err != nil || !status { + continue + } + + log.WithValues("at", cond.LastTransitionTime).Info("PendingRestart") + + restartTime, err := time.Parse(time.RFC3339, *cond.LastTransitionTime) + if err != nil { + continue + } + return restartTime, nil + } + + return time.Time{}, nil +} + +func scheduleRestart(ctx context.Context, iof *runtime.Runtime, compName string, restartTime time.Time) error { + name := fmt.Sprintf("pg-restart-%d", restartTime.Unix()) + ops := sgv1.SGDbOps{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: fmt.Sprintf("vshn-postgresql-%s", compName), + }, + Spec: sgv1.SGDbOpsSpec{ + Op: sgv1.SGDbOpsOpRestart, + SgCluster: compName, + Restart: &sgv1.SGDbOpsSpecRestart{ + Method: pointer.String(sgv1.SGDbOpsRestartMethodInPlace), + OnlyPendingRestart: pointer.Bool(true), + }, + RunAt: pointer.String(restartTime.Format(time.RFC3339)), + }, + } + return iof.Desired.PutIntoObject(ctx, &ops, fmt.Sprintf("%s-%s", compName, name)) +} + +func keepRecentRestartOps(ctx context.Context, iof *runtime.Runtime, compName string, now func() time.Time) error { + + for _, r := range iof.Observed.List(ctx) { + if !strings.HasPrefix(r.GetName(), fmt.Sprintf("%s-pg-restart", compName)) { + continue + } + + op := sgv1.SGDbOps{} + err := iof.Observed.GetFromObject(ctx, &op, r.GetName()) + if err != nil { + continue + } + + if op.Spec.Op != "restart" || op.Spec.RunAt == nil { + continue + } + + runAt, err := time.Parse(time.RFC3339, *op.Spec.RunAt) + if err != nil { + continue + } + + if runAt.Before(now().Add(-1 * sgDbOpsRestartRetention)) { + continue + } + + err = iof.Desired.PutIntoObject(ctx, &op, r.GetName()) + if err != nil { + return err + } + } + return nil +} diff --git a/functions/vshn-postgres-func/restart_test.go b/functions/vshn-postgres-func/restart_test.go new file mode 100644 index 0000000..020c351 --- /dev/null +++ b/functions/vshn-postgres-func/restart_test.go @@ -0,0 +1,92 @@ +package vshnpostgres + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + sgv1 "github.com/vshn/appcat-comp-functions/apis/stackgres/v1" + "github.com/vshn/appcat-comp-functions/runtime" + vshnv1 "github.com/vshn/component-appcat/apis/vshn/v1" + + fnv1aplha1 "github.com/crossplane/crossplane/apis/apiextensions/fn/io/v1alpha1" +) + +func TestTransformRestart_NoopNoPending(t *testing.T) { + iof := loadRuntimeFromFile(t, "restart/01-NoPendingReboot.yaml") + require.NoError(t, runtime.AddToScheme(sgv1.SchemeBuilder.SchemeBuilder)) + + res := TransformRestart(context.TODO(), iof) + assert.Equal(t, fnv1aplha1.SeverityNormal, res.Resolve().Severity, res.Resolve().Message) + + comp := &vshnv1.XVSHNPostgreSQL{} + err := iof.Desired.GetComposite(context.TODO(), comp) + assert.NoError(t, err) + + assert.Len(t, iof.Desired.List(context.TODO()), 0) +} +func TestTransformRestart_NoopPendingOnRestart(t *testing.T) { + iof := loadRuntimeFromFile(t, "restart/02-PendingRebootNoRestart.yaml") + require.NoError(t, runtime.AddToScheme(sgv1.SchemeBuilder.SchemeBuilder)) + + res := TransformRestart(context.TODO(), iof) + assert.Equal(t, fnv1aplha1.SeverityNormal, res.Resolve().Severity, res.Resolve().Message) + + comp := &vshnv1.XVSHNPostgreSQL{} + err := iof.Desired.GetComposite(context.TODO(), comp) + assert.NoError(t, err) + + assert.Len(t, iof.Desired.List(context.TODO()), 0) +} + +func TestTransformRestart_RestartPending(t *testing.T) { + iof := loadRuntimeFromFile(t, "restart/02-PendingReboot.yaml") + require.NoError(t, runtime.AddToScheme(sgv1.SchemeBuilder.SchemeBuilder)) + + res := TransformRestart(context.TODO(), iof) + assert.Equal(t, fnv1aplha1.SeverityNormal, res.Resolve().Severity, res.Resolve().Message) + + comp := &vshnv1.XVSHNPostgreSQL{} + err := iof.Desired.GetComposite(context.TODO(), comp) + assert.NoError(t, err) + + assert.Len(t, iof.Desired.List(context.TODO()), 1) + + sgrest := sgv1.SGDbOps{} + assert.NoError(t, iof.Desired.GetFromObject(context.TODO(), &sgrest, "pgsql-gc9x4-pg-restart-1682587342")) + assert.Equal(t, "restart", sgrest.Spec.Op) + if assert.NotNil(t, sgrest.Spec.RunAt) { + assert.Equal(t, "2023-04-27T09:22:22Z", *sgrest.Spec.RunAt) + } + if assert.NotNil(t, sgrest.Spec.Restart) { + if assert.NotNil(t, sgrest.Spec.Restart.Method) { + assert.Equal(t, "InPlace", *sgrest.Spec.Restart.Method) + } + if assert.NotNil(t, sgrest.Spec.Restart.OnlyPendingRestart) { + assert.True(t, *sgrest.Spec.Restart.OnlyPendingRestart) + } + } + assert.Equal(t, "restart", sgrest.Spec.Op) +} + +func TestTransformRestart_KeepRecentReboots(t *testing.T) { + iof := loadRuntimeFromFile(t, "restart/03-KeepRecentReboots.yaml") + require.NoError(t, runtime.AddToScheme(sgv1.SchemeBuilder.SchemeBuilder)) + + now := func() time.Time { + n, err := time.Parse(time.RFC3339, "2023-04-27T10:04:05Z") + assert.NoError(t, err) + return n + } + + res := transformRestart(context.TODO(), iof, now) + assert.Equal(t, fnv1aplha1.SeverityNormal, res.Resolve().Severity, res.Resolve().Message) + + comp := &vshnv1.XVSHNPostgreSQL{} + err := iof.Desired.GetComposite(context.TODO(), comp) + assert.NoError(t, err) + + assert.Len(t, iof.Desired.List(context.TODO()), 2) +} diff --git a/go.mod b/go.mod index e6e562a..e1471ab 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/sethvargo/go-password v0.2.0 github.com/stretchr/testify v1.8.1 github.com/urfave/cli/v2 v2.23.7 - github.com/vshn/component-appcat/apis v0.0.0-20230425231346-1af5398ee159 + github.com/vshn/component-appcat/apis v0.0.0-20230508083110-a8e04b7b9a13 go.uber.org/zap v1.24.0 google.golang.org/grpc v1.50.1 k8s.io/api v0.26.3 @@ -74,7 +74,7 @@ require ( github.com/spf13/cobra v1.6.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/valyala/fasttemplate v1.2.1 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect diff --git a/go.sum b/go.sum index c4e720d..1288a08 100644 --- a/go.sum +++ b/go.sum @@ -395,11 +395,12 @@ github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6f github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/vshn/component-appcat/apis v0.0.0-20230425231346-1af5398ee159 h1:mtiNMnPWcPWBS26ANetXB34cPp6WprCGPsLxWvshtDU= -github.com/vshn/component-appcat/apis v0.0.0-20230425231346-1af5398ee159/go.mod h1:CmhF7UOC1bivx++1x43BJfJaHj2eOG1d6GRJZQQoQvc= +github.com/vshn/component-appcat/apis v0.0.0-20230502150715-7f57fa574e3b h1:FYtjwjCM4iGpvLNxvZPV2c4PV+gSCtqkC3hjD3aRLxk= +github.com/vshn/component-appcat/apis v0.0.0-20230502150715-7f57fa574e3b/go.mod h1:+zmzGcEUhwhz3QlIMMo+XQTRSoIK8MY/kSlIcEzC6I8= +github.com/vshn/component-appcat/apis v0.0.0-20230508083110-a8e04b7b9a13 h1:GoRKKQzu7sUpp82v5+xqsIbWKtQZIv/vrS6+r5UzsaQ= +github.com/vshn/component-appcat/apis v0.0.0-20230508083110-a8e04b7b9a13/go.mod h1:+zmzGcEUhwhz3QlIMMo+XQTRSoIK8MY/kSlIcEzC6I8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/main.go b/main.go index e9e3002..293739e 100644 --- a/main.go +++ b/main.go @@ -9,10 +9,12 @@ import ( rt "runtime" "time" - pb "github.com/crossplane/crossplane/apis/apiextensions/fn/proto/v1alpha1" - "github.com/go-logr/logr" + sgv1 "github.com/vshn/appcat-comp-functions/apis/stackgres/v1" vp "github.com/vshn/appcat-comp-functions/functions/vshn-postgres-func" "github.com/vshn/appcat-comp-functions/runtime" + + pb "github.com/crossplane/crossplane/apis/apiextensions/fn/proto/v1alpha1" + "github.com/go-logr/logr" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -28,13 +30,17 @@ var AI = runtime.AppInfo{ var postgresFunctions = []runtime.Transform{ { - Name: "url-connection-details", + Name: "url-connection-detail", TransformFunc: vp.AddUrlToConnectionDetails, }, { Name: "user-alerting", TransformFunc: vp.AddUserAlerting, }, + { + Name: "restart", + TransformFunc: vp.TransformRestart, + }, { Name: "random-default-schedule", TransformFunc: vp.TransformSchedule, @@ -107,6 +113,11 @@ func main() { log.Fatalf("failed to listen: %v", err) } + err = runtime.AddToScheme(sgv1.SchemeBuilder.SchemeBuilder) + if err != nil { + log.Fatalf("failed register stackgres CRDs: %v", err) + } + s := grpc.NewServer() pb.RegisterContainerizedFunctionRunnerServiceServer(s, &server{logger: logger}) diff --git a/test/transforms/vshn-postgres/restart/01-NoPendingReboot.yaml b/test/transforms/vshn-postgres/restart/01-NoPendingReboot.yaml new file mode 100644 index 0000000..3ba4f75 --- /dev/null +++ b/test/transforms/vshn-postgres/restart/01-NoPendingReboot.yaml @@ -0,0 +1,195 @@ +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +observed: + composite: + resource: + apiVersion: vshn.appcat.vshn.io/v1 + kind: XVSHNPostgreSQL + metadata: + annotations: + creationTimestamp: "2023-03-21T16:52:31Z" + finalizers: + - composite.apiextensions.crossplane.io + generateName: pgsql- + generation: 13 + labels: + appuio.io/organization: vshn + crossplane.io/claim-name: pgsql + crossplane.io/claim-namespace: unit-test + crossplane.io/composite: pgsql-gc9x4 + name: pgsql-gc9x4 + spec: + claimRef: + apiVersion: vshn.appcat.vshn.io/v1 + kind: VSHNPostgreSQL + name: pgsql + namespace: unit-test + compositionRef: + name: vshnpostgres.vshn.appcat.vshn.io + compositionRevisionRef: + name: vshnpostgres.vshn.appcat.vshn.io-ce52f13 + compositionUpdatePolicy: Automatic + parameters: + updateStrategy: + type: "Immediate" + status: + instanceNamespace: my-psql + resources: + - name: cluster + resource: + apiVersion: kubernetes.crossplane.io/v1alpha1 + kind: Object + metadata: + name: pgsql-gc9x4-cluster + spec: + forProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGCluster + metadata: + name: psql-gc9x4 + namespace: vshn-postgresql-psql-gc9x4 + spec: + configurations: + backups: + - cronSchedule: 44 20 * * * + retention: 6 + sgObjectStorage: sgbackup-psql-gc9x4 + sgPostgresConfig: psql-gc9x4 + instances: 1 + nonProductionOptions: + enableSetPatroniCpuRequests: true + enableSetPatroniMemoryRequests: true + pods: + persistentVolume: + size: 20Gi + scheduling: + nodeSelector: {} + postgres: + ssl: + certificateSecretKeySelector: + key: tls.crt + name: tls-certificate + enabled: true + privateKeySecretKeySelector: + key: tls.key + name: tls-certificate + version: "15" + sgInstanceProfile: psql-gc9x4 + managementPolicy: Default + providerConfigRef: + name: kubernetes + status: + atProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGCluster + metadata: + annotations: + creationTimestamp: "2023-04-27T09:21:42Z" + generation: 8 + name: psql-gc9x4 + namespace: vshn-postgresql-psql-gc9x4 + resourceVersion: "583272583" + uid: 44ead047-98de-4e73-9cc0-d99454090a36 + spec: + configurations: + backups: + - cronSchedule: 44 20 * * * + path: sgbackups.stackgres.io/vshn-postgresql-psql-gc9x4/buzz-qvgrd/15 + retention: 6 + sgObjectStorage: sgbackup-psql-gc9x4 + sgPoolingConfig: generated-from-default-1682587302016 + sgPostgresConfig: psql-gc9x4 + instances: 1 + managedSql: + scripts: + - id: 0 + sgScript: psql-gc9x4-default + nonProductionOptions: + enableSetPatroniCpuRequests: true + enableSetPatroniMemoryRequests: true + pods: + persistentVolume: + size: 20Gi + scheduling: + nodeSelector: {} + postgres: + flavor: vanilla + ssl: + certificateSecretKeySelector: + key: tls.crt + name: tls-certificate + enabled: true + privateKeySecretKeySelector: + key: tls.key + name: tls-certificate + version: "15.1" + postgresServices: + primary: + enabled: true + type: ClusterIP + replicas: + enabled: true + type: ClusterIP + replication: + mode: async + role: ha-read + sgInstanceProfile: psql-gc9x4 + toInstallPostgresExtensions: [] + status: + arch: x86_64 + conditions: + - lastTransitionTime: "2023-04-27T09:22:22.200237Z" + reason: FalseFailed + status: "False" + type: Failed + - lastTransitionTime: "2023-04-27T09:22:22.226244Z" + reason: FalsePendingRestart + status: "False" + type: PendingRestart + - lastTransitionTime: "2023-04-27T09:22:22.226273Z" + reason: FalsePendingUpgrade + status: "False" + type: PendingUpgrade + managedSql: + scripts: + - completedAt: "2023-04-27T09:22:52.795696Z" + id: 0 + scripts: + - id: 0 + version: 0 + startedAt: "2023-04-27T09:22:52.631407Z" + updatedAt: "2023-04-27T09:22:52.631418Z" + os: linux + podStatuses: + - installedPostgresExtensions: [] + name: psql-gc9x4-0 + pendingRestart: false + primary: true + replicationGroup: 0 +desired: + composite: + connectionDetails: null + resource: + apiVersion: vshn.appcat.vshn.io/v1 + kind: XVSHNPostgreSQL + metadata: + creationTimestamp: "2023-03-21T16:52:31Z" + finalizers: + - composite.apiextensions.crossplane.io + generateName: pgsql- + generation: 13 + labels: + appuio.io/organization: vshn + crossplane.io/claim-name: pgsql + crossplane.io/claim-namespace: unit-test + crossplane.io/composite: pgsql-gc9x4 + name: pgsql-gc9x4 + spec: + parameters: + updateStrategy: + type: "Immediate" + writeConnectionSecretToRef: {} + status: + instanceNamespace: my-psql diff --git a/test/transforms/vshn-postgres/restart/02-PendingReboot.yaml b/test/transforms/vshn-postgres/restart/02-PendingReboot.yaml new file mode 100644 index 0000000..fb4b656 --- /dev/null +++ b/test/transforms/vshn-postgres/restart/02-PendingReboot.yaml @@ -0,0 +1,191 @@ +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +observed: + composite: + resource: + apiVersion: vshn.appcat.vshn.io/v1 + kind: XVSHNPostgreSQL + metadata: + annotations: + creationTimestamp: "2023-03-21T16:52:31Z" + finalizers: + - composite.apiextensions.crossplane.io + generateName: pgsql- + generation: 13 + labels: + appuio.io/organization: vshn + crossplane.io/claim-name: pgsql + crossplane.io/claim-namespace: unit-test + crossplane.io/composite: pgsql-gc9x4 + name: pgsql-gc9x4 + spec: + claimRef: + apiVersion: vshn.appcat.vshn.io/v1 + kind: VSHNPostgreSQL + name: pgsql + namespace: unit-test + compositionRef: + name: vshnpostgres.vshn.appcat.vshn.io + compositionRevisionRef: + name: vshnpostgres.vshn.appcat.vshn.io-ce52f13 + compositionUpdatePolicy: Automatic + parameters: {} + status: + instanceNamespace: my-psql + resources: + - name: cluster + resource: + apiVersion: kubernetes.crossplane.io/v1alpha1 + kind: Object + metadata: + name: pgsql-gc9x4-cluster + spec: + forProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGCluster + metadata: + name: psql-gc9x4 + namespace: vshn-postgresql-psql-gc9x4 + spec: + configurations: + backups: + - cronSchedule: 44 20 * * * + retention: 6 + sgObjectStorage: sgbackup-psql-gc9x4 + sgPostgresConfig: psql-gc9x4 + instances: 1 + nonProductionOptions: + enableSetPatroniCpuRequests: true + enableSetPatroniMemoryRequests: true + pods: + persistentVolume: + size: 20Gi + scheduling: + nodeSelector: {} + postgres: + ssl: + certificateSecretKeySelector: + key: tls.crt + name: tls-certificate + enabled: true + privateKeySecretKeySelector: + key: tls.key + name: tls-certificate + version: "15" + sgInstanceProfile: psql-gc9x4 + managementPolicy: Default + providerConfigRef: + name: kubernetes + status: + atProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGCluster + metadata: + annotations: + creationTimestamp: "2023-04-27T09:21:42Z" + generation: 8 + name: psql-gc9x4 + namespace: vshn-postgresq:error_budget:ratiol-psql-gc9x4 + resourceVersion: "583272583" + uid: 44ead047-98de-4e73-9cc0-d99454090a36 + spec: + configurations: + backups: + - cronSchedule: 44 20 * * * + path: sgbackups.stackgres.io/vshn-postgresql-psql-gc9x4/buzz-qvgrd/15 + retention: 6 + sgObjectStorage: sgbackup-psql-gc9x4 + sgPoolingConfig: generated-from-default-1682587302016 + sgPostgresConfig: psql-gc9x4 + instances: 1 + managedSql: + scripts: + - id: 0 + sgScript: psql-gc9x4-default + nonProductionOptions: + enableSetPatroniCpuRequests: true + enableSetPatroniMemoryRequests: true + pods: + persistentVolume: + size: 20Gi + scheduling: + nodeSelector: {} + postgres: + flavor: vanilla + ssl: + certificateSecretKeySelector: + key: tls.crt + name: tls-certificate + enabled: true + privateKeySecretKeySelector: + key: tls.key + name: tls-certificate + version: "15.1" + postgresServices: + primary: + enabled: true + type: ClusterIP + replicas: + enabled: true + type: ClusterIP + replication: + mode: async + role: ha-read + sgInstanceProfile: psql-gc9x4 + toInstallPostgresExtensions: [] + status: + arch: x86_64 + conditions: + - lastTransitionTime: "2023-04-27T09:22:22.200237Z" + reason: FalseFailed + status: "False" + type: Failed + - lastTransitionTime: "2023-04-27T09:22:22.226244Z" + reason: TruePendingRestart + status: "True" + type: PendingRestart + - lastTransitionTime: "2023-04-27T09:22:22.226273Z" + reason: FalsePendingUpgrade + status: "False" + type: PendingUpgrade + managedSql: + scripts: + - completedAt: "2023-04-27T09:22:52.795696Z" + id: 0 + scripts: + - id: 0 + version: 0 + startedAt: "2023-04-27T09:22:52.631407Z" + updatedAt: "2023-04-27T09:22:52.631418Z" + os: linux + podStatuses: + - installedPostgresExtensions: [] + name: psql-gc9x4-0 + pendingRestart: true + primary: true + replicationGroup: 0 +desired: + composite: + connectionDetails: null + resource: + apiVersion: vshn.appcat.vshn.io/v1 + kind: XVSHNPostgreSQL + metadata: + creationTimestamp: "2023-03-21T16:52:31Z" + finalizers: + - composite.apiextensions.crossplane.io + generateName: pgsql- + generation: 13 + labels: + appuio.io/organization: vshn + crossplane.io/claim-name: pgsql + crossplane.io/claim-namespace: unit-test + crossplane.io/composite: pgsql-gc9x4 + name: pgsql-gc9x4 + spec: + parameters: {} + writeConnectionSecretToRef: {} + status: + instanceNamespace: my-psql diff --git a/test/transforms/vshn-postgres/restart/02-PendingRebootNoRestart.yaml b/test/transforms/vshn-postgres/restart/02-PendingRebootNoRestart.yaml new file mode 100644 index 0000000..3a16a6f --- /dev/null +++ b/test/transforms/vshn-postgres/restart/02-PendingRebootNoRestart.yaml @@ -0,0 +1,195 @@ +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +observed: + composite: + resource: + apiVersion: vshn.appcat.vshn.io/v1 + kind: XVSHNPostgreSQL + metadata: + annotations: + creationTimestamp: "2023-03-21T16:52:31Z" + finalizers: + - composite.apiextensions.crossplane.io + generateName: pgsql- + generation: 13 + labels: + appuio.io/organization: vshn + crossplane.io/claim-name: pgsql + crossplane.io/claim-namespace: unit-test + crossplane.io/composite: pgsql-gc9x4 + name: pgsql-gc9x4 + spec: + claimRef: + apiVersion: vshn.appcat.vshn.io/v1 + kind: VSHNPostgreSQL + name: pgsql + namespace: unit-test + compositionRef: + name: vshnpostgres.vshn.appcat.vshn.io + compositionRevisionRef: + name: vshnpostgres.vshn.appcat.vshn.io-ce52f13 + compositionUpdatePolicy: Automatic + parameters: + updateStrategy: + type: "OnRestart" + status: + instanceNamespace: my-psql + resources: + - name: cluster + resource: + apiVersion: kubernetes.crossplane.io/v1alpha1 + kind: Object + metadata: + name: pgsql-gc9x4-cluster + spec: + forProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGCluster + metadata: + name: psql-gc9x4 + namespace: vshn-postgresql-psql-gc9x4 + spec: + configurations: + backups: + - cronSchedule: 44 20 * * * + retention: 6 + sgObjectStorage: sgbackup-psql-gc9x4 + sgPostgresConfig: psql-gc9x4 + instances: 1 + nonProductionOptions: + enableSetPatroniCpuRequests: true + enableSetPatroniMemoryRequests: true + pods: + persistentVolume: + size: 20Gi + scheduling: + nodeSelector: {} + postgres: + ssl: + certificateSecretKeySelector: + key: tls.crt + name: tls-certificate + enabled: true + privateKeySecretKeySelector: + key: tls.key + name: tls-certificate + version: "15" + sgInstanceProfile: psql-gc9x4 + managementPolicy: Default + providerConfigRef: + name: kubernetes + status: + atProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGCluster + metadata: + annotations: + creationTimestamp: "2023-04-27T09:21:42Z" + generation: 8 + name: psql-gc9x4 + namespace: vshn-postgresql-psql-gc9x4 + resourceVersion: "583272583" + uid: 44ead047-98de-4e73-9cc0-d99454090a36 + spec: + configurations: + backups: + - cronSchedule: 44 20 * * * + path: sgbackups.stackgres.io/vshn-postgresql-psql-gc9x4/buzz-qvgrd/15 + retention: 6 + sgObjectStorage: sgbackup-psql-gc9x4 + sgPoolingConfig: generated-from-default-1682587302016 + sgPostgresConfig: psql-gc9x4 + instances: 1 + managedSql: + scripts: + - id: 0 + sgScript: psql-gc9x4-default + nonProductionOptions: + enableSetPatroniCpuRequests: true + enableSetPatroniMemoryRequests: true + pods: + persistentVolume: + size: 20Gi + scheduling: + nodeSelector: {} + postgres: + flavor: vanilla + ssl: + certificateSecretKeySelector: + key: tls.crt + name: tls-certificate + enabled: true + privateKeySecretKeySelector: + key: tls.key + name: tls-certificate + version: "15.1" + postgresServices: + primary: + enabled: true + type: ClusterIP + replicas: + enabled: true + type: ClusterIP + replication: + mode: async + role: ha-read + sgInstanceProfile: psql-gc9x4 + toInstallPostgresExtensions: [] + status: + arch: x86_64 + conditions: + - lastTransitionTime: "2023-04-27T09:22:22.200237Z" + reason: FalseFailed + status: "False" + type: Failed + - lastTransitionTime: "2023-04-27T09:22:22.226244Z" + reason: TruePendingRestart + status: "True" + type: PendingRestart + - lastTransitionTime: "2023-04-27T09:22:22.226273Z" + reason: FalsePendingUpgrade + status: "False" + type: PendingUpgrade + managedSql: + scripts: + - completedAt: "2023-04-27T09:22:52.795696Z" + id: 0 + scripts: + - id: 0 + version: 0 + startedAt: "2023-04-27T09:22:52.631407Z" + updatedAt: "2023-04-27T09:22:52.631418Z" + os: linux + podStatuses: + - installedPostgresExtensions: [] + name: psql-gc9x4-0 + pendingRestart: true + primary: true + replicationGroup: 0 +desired: + composite: + connectionDetails: null + resource: + apiVersion: vshn.appcat.vshn.io/v1 + kind: XVSHNPostgreSQL + metadata: + creationTimestamp: "2023-03-21T16:52:31Z" + finalizers: + - composite.apiextensions.crossplane.io + generateName: pgsql- + generation: 13 + labels: + appuio.io/organization: vshn + crossplane.io/claim-name: pgsql + crossplane.io/claim-namespace: unit-test + crossplane.io/composite: pgsql-gc9x4 + name: pgsql-gc9x4 + spec: + parameters: + updateStrategy: + type: "OnRestart" + writeConnectionSecretToRef: {} + status: + instanceNamespace: my-psql diff --git a/test/transforms/vshn-postgres/restart/03-KeepRecentReboots.yaml b/test/transforms/vshn-postgres/restart/03-KeepRecentReboots.yaml new file mode 100644 index 0000000..36743e9 --- /dev/null +++ b/test/transforms/vshn-postgres/restart/03-KeepRecentReboots.yaml @@ -0,0 +1,291 @@ +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: FunctionIO +observed: + composite: + resource: + apiVersion: vshn.appcat.vshn.io/v1 + kind: XVSHNPostgreSQL + metadata: + annotations: + creationTimestamp: "2023-03-21T16:52:31Z" + finalizers: + - composite.apiextensions.crossplane.io + generateName: pgsql- + generation: 13 + labels: + appuio.io/organization: vshn + crossplane.io/claim-name: pgsql + crossplane.io/claim-namespace: unit-test + crossplane.io/composite: pgsql-gc9x4 + name: pgsql-gc9x4 + spec: + claimRef: + apiVersion: vshn.appcat.vshn.io/v1 + kind: VSHNPostgreSQL + name: pgsql + namespace: unit-test + compositionRef: + name: vshnpostgres.vshn.appcat.vshn.io + compositionRevisionRef: + name: vshnpostgres.vshn.appcat.vshn.io-ce52f13 + compositionUpdatePolicy: Automatic + parameters: + updateStrategy: + type: "OnRestart" + status: + instanceNamespace: my-psql + resources: + - name: cluster + resource: + apiVersion: kubernetes.crossplane.io/v1alpha1 + kind: Object + metadata: + name: pgsql-gc9x4-cluster + spec: + forProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGCluster + metadata: + name: psql-gc9x4 + namespace: vshn-postgresql-psql-gc9x4 + spec: + configurations: + backups: + - cronSchedule: 44 20 * * * + retention: 6 + sgObjectStorage: sgbackup-psql-gc9x4 + sgPostgresConfig: psql-gc9x4 + instances: 1 + nonProductionOptions: + enableSetPatroniCpuRequests: true + enableSetPatroniMemoryRequests: true + pods: + persistentVolume: + size: 20Gi + scheduling: + nodeSelector: {} + postgres: + ssl: + certificateSecretKeySelector: + key: tls.crt + name: tls-certificate + enabled: true + privateKeySecretKeySelector: + key: tls.key + name: tls-certificate + version: "15" + sgInstanceProfile: psql-gc9x4 + managementPolicy: Default + providerConfigRef: + name: kubernetes + status: + atProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGCluster + metadata: + annotations: + creationTimestamp: "2023-04-27T09:21:42Z" + generation: 8 + name: psql-gc9x4 + namespace: vshn-postgresql-psql-gc9x4 + resourceVersion: "583272583" + uid: 44ead047-98de-4e73-9cc0-d99454090a36 + spec: + configurations: + backups: + - cronSchedule: 44 20 * * * + path: sgbackups.stackgres.io/vshn-postgresql-psql-gc9x4/buzz-qvgrd/15 + retention: 6 + sgObjectStorage: sgbackup-psql-gc9x4 + sgPoolingConfig: generated-from-default-1682587302016 + sgPostgresConfig: psql-gc9x4 + instances: 1 + managedSql: + scripts: + - id: 0 + sgScript: psql-gc9x4-default + nonProductionOptions: + enableSetPatroniCpuRequests: true + enableSetPatroniMemoryRequests: true + pods: + persistentVolume: + size: 20Gi + scheduling: + nodeSelector: {} + postgres: + flavor: vanilla + ssl: + certificateSecretKeySelector: + key: tls.crt + name: tls-certificate + enabled: true + privateKeySecretKeySelector: + key: tls.key + name: tls-certificate + version: "15.1" + postgresServices: + primary: + enabled: true + type: ClusterIP + replicas: + enabled: true + type: ClusterIP + replication: + mode: async + role: ha-read + sgInstanceProfile: psql-gc9x4 + toInstallPostgresExtensions: [] + status: + arch: x86_64 + conditions: + - lastTransitionTime: "2023-04-27T09:22:22.200237Z" + reason: FalseFailed + status: "False" + type: Failed + - lastTransitionTime: "2023-04-27T09:22:22.226244Z" + reason: TruePendingRestart + status: "True" + type: PendingRestart + - lastTransitionTime: "2023-04-27T09:22:22.226273Z" + reason: FalsePendingUpgrade + status: "False" + type: PendingUpgrade + managedSql: + scripts: + - completedAt: "2023-04-27T09:22:52.795696Z" + id: 0 + scripts: + - id: 0 + version: 0 + startedAt: "2023-04-27T09:22:52.631407Z" + updatedAt: "2023-04-27T09:22:52.631418Z" + os: linux + podStatuses: + - installedPostgresExtensions: [] + name: psql-gc9x4-0 + pendingRestart: true + primary: true + replicationGroup: 0 + - name: pgsql-gc9x4-pg-restart-1682587342 + resource: + apiVersion: kubernetes.crossplane.io/v1alpha1 + kind: Object + metadata: + name: pgsql-gc9x4-pg-restart-1682587342 + spec: + forProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGDbOps + metadata: + name: pg-restart-1682587342 + namespace: vshn-postgresql-psql-gc9x4 + spec: + op: restart + runAt: "2023-04-27T09:22:22Z" + sgCluster: psql-gc9x4 + status: {} + status: + atProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGDbOps + metadata: + name: pg-restart-1682587342 + namespace: vshn-postgresql-psql-gc9x4 + spec: + op: restart + runAt: "2023-04-27T09:22:22Z" + sgCluster: psql-gc9x4 + status: {} + - name: pgsql-gc9x4-pg-restart-1682493742 + resource: + apiVersion: kubernetes.crossplane.io/v1alpha1 + kind: Object + metadata: + name: pgsql-gc9x4-pg-restart-1682493742 + spec: + forProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGDbOps + metadata: + name: pg-restart-1682493742 + namespace: vshn-postgresql-psql-gc9x4 + spec: + op: restart + runAt: "2023-04-26T07:22:22Z" + sgCluster: psql-gc9x4 + status: {} + status: + atProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGDbOps + metadata: + name: pg-restart-1682493742 + namespace: vshn-postgresql-psql-gc9x4 + spec: + op: restart + runAt: "2023-04-26T07:22:22Z" + sgCluster: psql-gc9x4 + status: {} + - name: pgsql-gc9x4-pg-restart-1679815342 + resource: + apiVersion: kubernetes.crossplane.io/v1alpha1 + kind: Object + metadata: + name: pgsql-gc9x4-pg-restart-1679815342 + spec: + forProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGDbOps + metadata: + name: pg-restart-1679815342 + namespace: vshn-postgresql-psql-gc9x4 + spec: + op: restart + runAt: "2023-03-26T07:22:22Z" + sgCluster: psql-gc9x4 + status: {} + status: + atProvider: + manifest: + apiVersion: stackgres.io/v1 + kind: SGDbOps + metadata: + name: pg-restart-1679815342 + namespace: vshn-postgresql-psql-gc9x4 + spec: + op: restart + runAt: "2023-03-26T07:22:22Z" + sgCluster: psql-gc9x4 + status: {} +desired: + composite: + connectionDetails: null + resource: + apiVersion: vshn.appcat.vshn.io/v1 + kind: XVSHNPostgreSQL + metadata: + creationTimestamp: "2023-03-21T16:52:31Z" + finalizers: + - composite.apiextensions.crossplane.io + generateName: pgsql- + generation: 13 + labels: + appuio.io/organization: vshn + crossplane.io/claim-name: pgsql + crossplane.io/claim-namespace: unit-test + crossplane.io/composite: pgsql-gc9x4 + name: pgsql-gc9x4 + spec: + parameters: + updateStrategy: + type: "OnRestart" + writeConnectionSecretToRef: {} + status: + instanceNamespace: my-psql