From be3c889e9294879b0e15adaf7cfee76466fbd946 Mon Sep 17 00:00:00 2001 From: Dmitriy Alekseev <1865999+dragoangel@users.noreply.github.com> Date: Sat, 31 Aug 2024 03:33:25 +0200 Subject: [PATCH] feat(cluster): Add support for replication and import, volumeSnapshot recovery Signed-off-by: Dmitriy Alekseev <1865999+dragoangel@users.noreply.github.com> --- charts/cluster/README.md | 177 +++--- charts/cluster/README.md.gotmpl | 10 +- charts/cluster/docs/Getting Started.md | 10 +- charts/cluster/docs/Recovery.md | 14 +- charts/cluster/examples/basic.yaml | 3 +- charts/cluster/examples/custom-queries.yaml | 4 +- .../cluster/examples/import-microservice.yaml | 23 + .../examples/import-monolith-full.yaml | 26 + charts/cluster/examples/import-monolith.yaml | 29 + charts/cluster/examples/pgbouncer.yaml | 4 +- charts/cluster/examples/postgis.yaml | 4 +- charts/cluster/examples/recovery-backup.yaml | 28 +- .../examples/recovery-object_store-aws.yaml | 33 + .../examples/recovery-object_store-minio.yaml | 40 ++ .../examples/recovery-object_store.yaml | 30 - .../recovery-pg_basebackup-password.yaml | 17 + .../examples/recovery-pg_basebackup-tls.yaml | 25 + .../examples/recovery-pg_basebackup.yaml | 14 - .../examples/recovery-volume_snapshot.yaml | 21 + .../examples/replica-distributed-primary.yaml | 37 ++ .../examples/replica-distributed-replica.yaml | 37 ++ .../cluster/examples/replica-standalone.yaml | 20 + charts/cluster/examples/standalone-s3.yaml | 19 +- charts/cluster/templates/NOTES.txt | 40 +- charts/cluster/templates/_backup.tpl | 33 +- .../templates/_barman_object_store.tpl | 26 +- charts/cluster/templates/_bootstrap.tpl | 169 ++++-- charts/cluster/templates/_helpers.tpl | 207 ++++++- .../cluster/templates/backup-azure-creds.yaml | 12 +- .../templates/backup-google-creds.yaml | 6 +- charts/cluster/templates/backup-s3-creds.yaml | 8 +- charts/cluster/templates/ca-bundle.yaml | 7 +- charts/cluster/templates/cluster.yaml | 27 +- charts/cluster/templates/pooler.yaml | 2 +- charts/cluster/templates/prometheus-rule.yaml | 2 +- .../templates/recovery-azure-creds.yaml | 12 +- .../templates/recovery-google-creds.yaml | 6 +- .../recovery-pg_basebackup-password.yaml | 8 - .../templates/recovery-pgbb-creds.yaml | 14 + .../cluster/templates/recovery-s3-creds.yaml | 8 +- .../cluster/templates/scheduled-backups.yaml | 15 +- .../monitoring/01-monitoring_cluster.yaml | 4 +- .../test/pooler/01-pooler_cluster.yaml | 4 +- .../01-non_default_configuration_cluster.yaml | 4 +- .../01-standalone_cluster.yaml | 34 +- .../05-recovery_backup_cluster.yaml | 55 +- .../07-recovery_object_store_cluster.yaml | 67 +-- .../09-recovery_backup_pitr_cluster.yaml | 55 +- .../00-source-cluster.yaml | 5 +- .../02-pg_basebackup-cluster.yaml | 30 +- charts/cluster/values.schema.json | 568 +++++++++++------- charts/cluster/values.yaml | 419 ++++++++----- 52 files changed, 1605 insertions(+), 867 deletions(-) create mode 100644 charts/cluster/examples/import-microservice.yaml create mode 100644 charts/cluster/examples/import-monolith-full.yaml create mode 100644 charts/cluster/examples/import-monolith.yaml create mode 100644 charts/cluster/examples/recovery-object_store-aws.yaml create mode 100644 charts/cluster/examples/recovery-object_store-minio.yaml delete mode 100644 charts/cluster/examples/recovery-object_store.yaml create mode 100644 charts/cluster/examples/recovery-pg_basebackup-password.yaml create mode 100644 charts/cluster/examples/recovery-pg_basebackup-tls.yaml delete mode 100644 charts/cluster/examples/recovery-pg_basebackup.yaml create mode 100644 charts/cluster/examples/recovery-volume_snapshot.yaml create mode 100644 charts/cluster/examples/replica-distributed-primary.yaml create mode 100644 charts/cluster/examples/replica-distributed-replica.yaml create mode 100644 charts/cluster/examples/replica-standalone.yaml delete mode 100644 charts/cluster/templates/recovery-pg_basebackup-password.yaml create mode 100644 charts/cluster/templates/recovery-pgbb-creds.yaml diff --git a/charts/cluster/README.md b/charts/cluster/README.md index 4c1265d5c..56294144f 100644 --- a/charts/cluster/README.md +++ b/charts/cluster/README.md @@ -75,10 +75,10 @@ The chart has three modes of operation. These are configured via the `mode` para CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are -stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following -providers are supported: +stored in the specified location. The backup provider is configured via the `backups.objectStorage.provider` parameter. +The following providers are supported: -* S3 or S3-compatible stores, like MinIO +* S3 or S3-compatible stores, like MinIO or Ceph Rados * Microsoft Azure Blob Storage * Google Cloud Storage @@ -94,8 +94,8 @@ backups: ``` Each backup adapter takes it's own set of parameters, listed in the [Configuration options](#Configuration-options) section -below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, -`backup.azure`, or `backup.google`. +below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: +`backups.objectStorage.providerSettings.s3`, `backups.objectStorage.providerSettings.azure` or `backups.objectStorage.providerSettings.google`. Recovery -------- @@ -112,42 +112,49 @@ refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentat | Key | Type | Default | Description | |-----|------|---------|-------------| -| backups.azure.connectionString | string | `""` | | -| backups.azure.containerName | string | `""` | | -| backups.azure.inheritFromAzureAD | bool | `false` | | -| backups.azure.path | string | `"/"` | | -| backups.azure.serviceName | string | `"blob"` | | -| backups.azure.storageAccount | string | `""` | | -| backups.azure.storageKey | string | `""` | | -| backups.azure.storageSasToken | string | `""` | | -| backups.data.compression | string | `"gzip"` | Data compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. | -| backups.data.encryption | string | `"AES256"` | Whether to instruct the storage provider to encrypt data files. One of `` (use the storage container default), `AES256` or `aws:kms`. | -| backups.data.jobs | int | `2` | Number of data files to be archived or restored in parallel. | -| backups.destinationPath | string | `""` | Overrides the provider specific default path. Defaults to: S3: s3:// Azure: https://..core.windows.net/ Google: gs:// | -| backups.enabled | bool | `false` | You need to configure backups manually, so backups are disabled by default. | -| backups.endpointCA | object | `{"create":false,"key":"","name":"","value":""}` | Specifies a CA bundle to validate a privately signed certificate. | -| backups.endpointCA.create | bool | `false` | Creates a secret with the given value if true, otherwise uses an existing secret. | -| backups.endpointURL | string | `""` | Overrides the provider specific default endpoint. Defaults to: S3: https://s3..amazonaws.com" | -| backups.google.applicationCredentials | string | `""` | | -| backups.google.bucket | string | `""` | | -| backups.google.gkeEnvironment | bool | `false` | | -| backups.google.path | string | `"/"` | | -| backups.provider | string | `"s3"` | One of `s3`, `azure` or `google` | +| backups.existingSecret.name | string | `""` | If the secret name is set, helm chart will create one which needed. Existing secret should contains all required veriables for chosen provider. | +| backups.objectStorage.data.compression | string | `"gzip"` | Data compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. | +| backups.objectStorage.data.encryption | string | `"AES256"` | Whether to instruct the storage provider to encrypt data files. One of `` (use the storage container default), `AES256` or `aws:kms`. | +| backups.objectStorage.data.jobs | int | `2` | Number of data files to be archived or restored in parallel. | +| backups.objectStorage.destinationPath | string | `""` | Overrides the provider specific default path. Defaults to: S3: s3:// Azure: https://..core.windows.net/ Google: gs:// | +| backups.objectStorage.endpointCA.create | bool | `false` | Specifies a CA bundle to validate a privately signed certificate. Creates a secret with the given value if true, otherwise uses an existing secret. | +| backups.objectStorage.endpointCA.key | string | `""` | | +| backups.objectStorage.endpointCA.name | string | `""` | | +| backups.objectStorage.endpointCA.value | string | `""` | | +| backups.objectStorage.endpointURL | string | `""` | Overrides the provider specific default endpoint. Defaults to: S3: https://s3..amazonaws.com" | +| backups.objectStorage.provider | string | `""` | Enables objectStorage provider. One of providers from `providerSettings`, empty string - disables objectStorage backups. https://cloudnative-pg.io/documentation/current/appendixes/object_stores/#appendix-a-common-object-stores-for-backups | +| backups.objectStorage.providerSettings.azure.connectionString | string | `""` | Configures `AZURE_CONNECTION_STRING` in secret | +| backups.objectStorage.providerSettings.azure.containerName | string | `""` | | +| backups.objectStorage.providerSettings.azure.inheritFromAzureAD | bool | `false` | | +| backups.objectStorage.providerSettings.azure.path | string | `"/"` | | +| backups.objectStorage.providerSettings.azure.serviceName | string | `"blob"` | | +| backups.objectStorage.providerSettings.azure.storageAccount | string | `""` | Configures `AZURE_STORAGE_ACCOUNT` in secret | +| backups.objectStorage.providerSettings.azure.storageKey | string | `""` | Configures `AZURE_STORAGE_KEY` in secret | +| backups.objectStorage.providerSettings.azure.storageSasToken | string | `""` | Configures `AZURE_STORAGE_SAS_TOKEN` in secret | +| backups.objectStorage.providerSettings.google.applicationCredentials | string | `""` | Configures `APPLICATION_CREDENTIALS` in secret | +| backups.objectStorage.providerSettings.google.bucket | string | `""` | | +| backups.objectStorage.providerSettings.google.gkeEnvironment | bool | `false` | | +| backups.objectStorage.providerSettings.google.path | string | `"/"` | | +| backups.objectStorage.providerSettings.s3.accessKey | string | `""` | Configures `ACCESS_KEY_ID` in secret | +| backups.objectStorage.providerSettings.s3.bucket | string | `""` | | +| backups.objectStorage.providerSettings.s3.path | string | `"/"` | | +| backups.objectStorage.providerSettings.s3.region | string | `""` | | +| backups.objectStorage.providerSettings.s3.secretKey | string | `""` | Configures `ACCESS_SECRET_KEY` in secret | +| backups.objectStorage.wal.compression | string | `"gzip"` | WAL compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. | +| backups.objectStorage.wal.encryption | string | `"AES256"` | Whether to instruct the storage provider to encrypt WAL files. One of `` (use the storage container default), `AES256` or `aws:kms`. | +| backups.objectStorage.wal.maxParallel | int | `1` | Number of WAL files to be archived or restored in parallel. | | backups.retentionPolicy | string | `"30d"` | Retention policy for backups | -| backups.s3.accessKey | string | `""` | | -| backups.s3.bucket | string | `""` | | -| backups.s3.path | string | `"/"` | | -| backups.s3.region | string | `""` | | -| backups.s3.secretKey | string | `""` | | | backups.scheduledBackups[0].backupOwnerReference | string | `"self"` | Backup owner reference | | backups.scheduledBackups[0].method | string | `"barmanObjectStore"` | Backup method, can be `barmanObjectStore` (default) or `volumeSnapshot` | | backups.scheduledBackups[0].name | string | `"daily-backup"` | Scheduled backup name | | backups.scheduledBackups[0].schedule | string | `"0 0 0 * * *"` | Schedule in cron format | -| backups.secret.create | bool | `true` | Whether to create a secret for the backup credentials | -| backups.secret.name | string | `""` | Name of the backup credentials secret | -| backups.wal.compression | string | `"gzip"` | WAL compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. | -| backups.wal.encryption | string | `"AES256"` | Whether to instruct the storage provider to encrypt WAL files. One of `` (use the storage container default), `AES256` or `aws:kms`. | -| backups.wal.maxParallel | int | `1` | Number of WAL files to be archived or restored in parallel. | +| backups.target | string | `"prefer-standby"` | Backup target configuration. One of `prefer-standby`, `primary`. https://cloudnative-pg.io/documentation/current/backup/#backup-from-a-standby | +| backups.volumeSnapshot.className | string | `""` | To enable volumeSnapshot configure className and add scheduledBackup with method `volumeSnapshot` https://cloudnative-pg.io/documentation/current/backup_volumesnapshot/#how-to-configure-volume-snapshot-backups | +| backups.volumeSnapshot.online | bool | `true` | Hot and cold backups https://cloudnative-pg.io/documentation/current/backup_volumesnapshot/#hot-and-cold-backups | +| backups.volumeSnapshot.onlineConfiguration.immediateCheckpoint | bool | `true` | | +| backups.volumeSnapshot.onlineConfiguration.waitForArchive | bool | `true` | | +| backups.volumeSnapshot.snapshotOwnerReference | string | `"backup"` | Persistence of volume snapshot objects https://cloudnative-pg.io/documentation/current/backup_volumesnapshot/#persistence-of-volume-snapshot-objects One of `none`, `backup`, `cluster`, note: `retentionPolicy` will work only with `backup` | +| backups.volumeSnapshot.walClassName | string | `""` | WAL snapshots class name, if empty - defaults to `className` | | cluster.additionalLabels | object | `{}` | | | cluster.affinity | object | `{"topologyKey":"topology.kubernetes.io/zone"}` | Affinity/Anti-affinity rules for Pods. See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-AffinityConfiguration | | cluster.annotations | object | `{}` | | @@ -178,7 +185,13 @@ refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentat | cluster.walStorage.size | string | `"1Gi"` | | | cluster.walStorage.storageClass | string | `""` | | | fullnameOverride | string | `""` | Override the full name of the chart | -| mode | string | `"standalone"` | Cluster mode of operation. Available modes: * `standalone` - default mode. Creates new or updates an existing CNPG cluster. * `replica` - Creates a replica cluster from an existing CNPG cluster. # TODO * `recovery` - Same as standalone but creates a cluster from a backup, object store or via pg_basebackup. | +| import.type | string | `""` | Choose one of types from `typeSettings`, https://cloudnative-pg.io/documentation/current/database_import/ All types require: configure `recovery.method` to `pgBasebackup` and `recovery.methodSettings` accordingly Please be aware off https://cloudnative-pg.io/documentation/current/database_import/#import-optimizations | +| import.typeSettings.microservice.database | string | `""` | Database name to import | +| import.typeSettings.microservice.owner | string | `""` | Configure database owner, defaults to the database name | +| import.typeSettings.microservice.postImportApplicationSQL | list | `[]` | Execute defined SQL queries in the application database after import, optional | +| import.typeSettings.monolith.databases | list | `[]` | List of databases that is required by the imported. Wildcard allow to import all databases. | +| import.typeSettings.monolith.roles | list | `[]` | List of role that is required by the imported databases. Wildcard allow to import all roles. Notes: 1. postgres, streaming_replica & cnp_pooler_pgbouncer roles will not be imported from origin 2. the SUPERUSER option is removed from any imported role | +| mode | string | `"standalone"` | Cluster mode of operation. Available modes: * `standalone` - default mode. Creates new or updates an existing CNPG cluster. * `import` - Creates a cluster by utilizing `pg_dump -Fc` from existing PostgreSQL, allows to migrate even from very old versions of PostgreSQL. * `recovery` - Creates a cluster from a backup, object store, pg_basebackup or volumeSnapshot. * `replica` - Creates a replica cluster from object store or pg_basebackup with settings defined in recovery method. | | nameOverride | string | `""` | Override the name of the chart | | pooler.enabled | bool | `false` | Whether to enable PgBouncer | | pooler.instances | int | `3` | Number of PgBouncer instances | @@ -188,52 +201,50 @@ refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentat | pooler.poolMode | string | `"transaction"` | PgBouncer pooling mode | | pooler.template | object | `{}` | Custom PgBouncer deployment template. Use to override image, specify resources, etc. | | pooler.type | string | `"rw"` | PgBouncer type of service to forward traffic to. | -| recovery.azure.connectionString | string | `""` | | -| recovery.azure.containerName | string | `""` | | -| recovery.azure.inheritFromAzureAD | bool | `false` | | -| recovery.azure.path | string | `"/"` | | -| recovery.azure.serviceName | string | `"blob"` | | -| recovery.azure.storageAccount | string | `""` | | -| recovery.azure.storageKey | string | `""` | | -| recovery.azure.storageSasToken | string | `""` | | -| recovery.backupName | string | `""` | Backup Recovery Method | -| recovery.clusterName | string | `""` | The original cluster name when used in backups. Also known as serverName. | -| recovery.destinationPath | string | `""` | Overrides the provider specific default path. Defaults to: S3: s3:// Azure: https://..core.windows.net/ Google: gs:// | -| recovery.endpointCA | object | `{"create":false,"key":"","name":"","value":""}` | Specifies a CA bundle to validate a privately signed certificate. | -| recovery.endpointCA.create | bool | `false` | Creates a secret with the given value if true, otherwise uses an existing secret. | -| recovery.endpointURL | string | `""` | Overrides the provider specific default endpoint. Defaults to: S3: https://s3..amazonaws.com" Leave empty if using the default S3 endpoint | -| recovery.google.applicationCredentials | string | `""` | | -| recovery.google.bucket | string | `""` | | -| recovery.google.gkeEnvironment | bool | `false` | | -| recovery.google.path | string | `"/"` | | -| recovery.method | string | `"backup"` | Available recovery methods: * `backup` - Recovers a CNPG cluster from a CNPG backup (PITR supported) Needs to be on the same cluster in the same namespace. * `object_store` - Recovers a CNPG cluster from a barman object store (PITR supported). * `pg_basebackup` - Recovers a CNPG cluster viaa streaming replication protocol. Useful if you want to migrate databases to CloudNativePG, even from outside Kubernetes. # TODO | -| recovery.pgBaseBackup.database | string | `"app"` | Name of the database used by the application. Default: `app`. | -| recovery.pgBaseBackup.owner | string | `""` | Name of the secret containing the initial credentials for the owner of the user database. If empty a new secret will be created from scratch | -| recovery.pgBaseBackup.secret | string | `""` | Name of the owner of the database in the instance to be used by applications. Defaults to the value of the `database` key. | -| recovery.pgBaseBackup.source.database | string | `"app"` | | -| recovery.pgBaseBackup.source.host | string | `""` | | -| recovery.pgBaseBackup.source.passwordSecret.create | bool | `false` | Whether to create a secret for the password | -| recovery.pgBaseBackup.source.passwordSecret.key | string | `"password"` | The key in the secret containing the password | -| recovery.pgBaseBackup.source.passwordSecret.name | string | `""` | Name of the secret containing the password | -| recovery.pgBaseBackup.source.passwordSecret.value | string | `""` | The password value to use when creating the secret | -| recovery.pgBaseBackup.source.port | int | `5432` | | -| recovery.pgBaseBackup.source.sslCertSecret.key | string | `""` | | -| recovery.pgBaseBackup.source.sslCertSecret.name | string | `""` | | -| recovery.pgBaseBackup.source.sslKeySecret.key | string | `""` | | -| recovery.pgBaseBackup.source.sslKeySecret.name | string | `""` | | -| recovery.pgBaseBackup.source.sslMode | string | `"verify-full"` | | -| recovery.pgBaseBackup.source.sslRootCertSecret.key | string | `""` | | -| recovery.pgBaseBackup.source.sslRootCertSecret.name | string | `""` | | -| recovery.pgBaseBackup.source.username | string | `""` | | -| recovery.pitrTarget.time | string | `""` | Time in RFC3339 format | -| recovery.provider | string | `"s3"` | One of `s3`, `azure` or `google` | -| recovery.s3.accessKey | string | `""` | | -| recovery.s3.bucket | string | `""` | | -| recovery.s3.path | string | `"/"` | | -| recovery.s3.region | string | `""` | | -| recovery.s3.secretKey | string | `""` | | -| recovery.secret.create | bool | `true` | Whether to create a secret for the backup credentials | -| recovery.secret.name | string | `""` | Name of the backup credentials secret | +| recovery.existingSecret.name | string | `""` | If the secret name is set, helm chart will create one which needed. Existing secret should contains all required veriables for chosen method or provider. | +| recovery.method | string | `""` | One of methods from `methodSettings`. | +| recovery.methodSettings.backup.name | string | `""` | Recovers a CNPG cluster from a backups.postgresql.cnpg.io custom resource (PITR supported). https://cloudnative-pg.io/documentation/current/recovery/#recovery-from-a-backup-object Needs to be on the same cluster in the same namespace. Name of the backup to recover from. | +| recovery.methodSettings.objectStorage.clusterName | string | `""` | Recovers a CNPG cluster from a barman object store (PITR supported). https://cloudnative-pg.io/documentation/current/recovery/#recovery-from-an-object-store https://cloudnative-pg.io/documentation/current/replica_cluster/#example-of-standalone-replica-cluster-from-an-object-store The original cluster name when used in backups. Also known as serverName. | +| recovery.methodSettings.objectStorage.destinationPath | string | `""` | Overrides the provider specific default path. Defaults to: S3: s3:// Azure: https://..core.windows.net/ Google: gs:// | +| recovery.methodSettings.objectStorage.endpointCA | object | `{"create":false,"key":"","name":"","value":""}` | Specifies a CA bundle to validate a privately signed certificate. | +| recovery.methodSettings.objectStorage.endpointCA.create | bool | `false` | Creates a secret with the given value if true, otherwise uses an existing secret. | +| recovery.methodSettings.objectStorage.endpointURL | string | `""` | Overrides the provider specific default endpoint. Defaults to: S3: https://s3..amazonaws.com" Leave empty if using the default S3 endpoint | +| recovery.methodSettings.objectStorage.provider | string | `""` | Enables objectStorage provider. One of providers from `providerSettings`. https://cloudnative-pg.io/documentation/current/appendixes/object_stores/#appendix-a-common-object-stores-for-backups | +| recovery.methodSettings.objectStorage.providerSettings.azure.connectionString | string | `""` | Configures `AZURE_CONNECTION_STRING` in secret | +| recovery.methodSettings.objectStorage.providerSettings.azure.containerName | string | `""` | | +| recovery.methodSettings.objectStorage.providerSettings.azure.inheritFromAzureAD | bool | `false` | | +| recovery.methodSettings.objectStorage.providerSettings.azure.path | string | `"/"` | | +| recovery.methodSettings.objectStorage.providerSettings.azure.serviceName | string | `"blob"` | | +| recovery.methodSettings.objectStorage.providerSettings.azure.storageAccount | string | `""` | Configures `AZURE_STORAGE_ACCOUNT` in secret | +| recovery.methodSettings.objectStorage.providerSettings.azure.storageKey | string | `""` | Configures `AZURE_STORAGE_KEY` in secret | +| recovery.methodSettings.objectStorage.providerSettings.azure.storageSasToken | string | `""` | Configures `AZURE_STORAGE_SAS_TOKEN` in secret | +| recovery.methodSettings.objectStorage.providerSettings.google.applicationCredentials | string | `""` | Configures `APPLICATION_CREDENTIALS` in secret | +| recovery.methodSettings.objectStorage.providerSettings.google.bucket | string | `""` | | +| recovery.methodSettings.objectStorage.providerSettings.google.gkeEnvironment | bool | `false` | | +| recovery.methodSettings.objectStorage.providerSettings.google.path | string | `"/"` | | +| recovery.methodSettings.objectStorage.providerSettings.s3.accessKey | string | `""` | Configures `ACCESS_KEY_ID` in secret | +| recovery.methodSettings.objectStorage.providerSettings.s3.bucket | string | `""` | | +| recovery.methodSettings.objectStorage.providerSettings.s3.path | string | `"/"` | | +| recovery.methodSettings.objectStorage.providerSettings.s3.region | string | `""` | | +| recovery.methodSettings.objectStorage.providerSettings.s3.secretKey | string | `""` | Configures `ACCESS_SECRET_KEY` in secret | +| recovery.methodSettings.pgBasebackup.auth | string | `"password"` | Configure one of supported auth types: `password` or `tls` | +| recovery.methodSettings.pgBasebackup.authDetails.password | string | `""` | Configures `password` in secret | +| recovery.methodSettings.pgBasebackup.authDetails.tls.ca | string | `""` | Configures `ca.crt` in secret | +| recovery.methodSettings.pgBasebackup.authDetails.tls.crt | string | `""` | Configures `tls.crt` in secret | +| recovery.methodSettings.pgBasebackup.authDetails.tls.key | string | `""` | Configures `tls.key` in secret | +| recovery.methodSettings.pgBasebackup.connectionParameters | object | `{"database":"","host":"","port":5432,"sslMode":"verify-full","user":""}` | Recovers a CNPG cluster via streaming replication protocol. https://cloudnative-pg.io/documentation/current/bootstrap/#bootstrap-from-a-live-cluster-pg_basebackup https://cloudnative-pg.io/documentation/current/replica_cluster/#example-of-standalone-replica-cluster-using-pg_basebackup | +| recovery.methodSettings.pgBasebackup.connectionParameters.database | string | `""` | Database on source server, optional. If `pgBasebackup.database` set and this setting is empty - will use same database name. | +| recovery.methodSettings.pgBasebackup.connectionParameters.sslMode | string | `"verify-full"` | SSL mode to use while connecting to host. Possible secure options: `verify-full`, `verify-ca`, `require` and insecure: `prefer`, `allow`, `disable`. For more details please see: https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-PROTECTION | +| recovery.methodSettings.pgBasebackup.database | string | `""` | Configure application database, optional and ignored with replica https://cloudnative-pg.io/documentation/current/bootstrap/#configure-the-application-database | +| recovery.methodSettings.pgBasebackup.owner | string | `""` | Configure database owner, defaults to the database name | +| recovery.methodSettings.pgBasebackup.ownerSecret | string | `""` | Name of the secret containing the initial credentials for the owner of the user database. Secret must contains `username` key that match `owner` and `password` key. If empty - password will be generated randomly and saved to secret generated by Operator. | +| recovery.methodSettings.volumeSnapshot.storageSnapshotName | string | `""` | Recovers a CNPG cluster from a volume snapshot (PITR supported). https://cloudnative-pg.io/documentation/current/recovery/#recovery-from-volumesnapshot-objects | +| recovery.methodSettings.volumeSnapshot.walSnapshotName | string | `""` | WAL snapshot name, optional, need to be set if WAL stored on separate PVC. | +| recovery.pitrTarget.time | string | `""` | Point in time recovery target. Work with backup, objectStorage and volumeSnapshot methods. Time should be set in RFC3339 format. | +| replica.topology | string | `""` | Choose one of topologies from `topologySettings`, https://cloudnative-pg.io/documentation/current/replica_cluster/ standalone: configure `recovery.method` to one of `objectStorage` or `pgBasebackup` and `recovery.methodSettings` accordingly distributed: configure `recovery.method` to `objectStorage` and `recovery.methodSettings` | +| replica.topologySettings.distributed.primary | bool | `true` | Distributed topology requires to use objectStorage in both recovery and backups | +| replica.topologySettings.distributed.promotionToken | string | `""` | Promoting a Replica to a Primary Cluster demotionToken obtrained from demoted primary should set to promotionToken on replica Use `kubectl get cluster cluster-eu-south -o jsonpath='{.status.demotionToken}'` https://cloudnative-pg.io/documentation/current/replica_cluster/#demoting-a-primary-to-a-replica-cluster https://cloudnative-pg.io/documentation/current/replica_cluster/#promoting-a-replica-to-a-primary-cluster | +| replica.topologySettings.standalone.minApplyDelay | string | `""` | Deleyed replication, disabled if empty, set enable set time, f.e: 1h https://cloudnative-pg.io/documentation/current/replica_cluster/#delayed-replicas | | type | string | `"postgresql"` | Type of the CNPG database. Available types: * `postgresql` * `postgis` | ## Maintainers diff --git a/charts/cluster/README.md.gotmpl b/charts/cluster/README.md.gotmpl index e1a4d2f05..08b05281e 100644 --- a/charts/cluster/README.md.gotmpl +++ b/charts/cluster/README.md.gotmpl @@ -83,10 +83,10 @@ The chart has three modes of operation. These are configured via the `mode` para CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are -stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following -providers are supported: +stored in the specified location. The backup provider is configured via the `backups.objectStorage.provider` parameter. +The following providers are supported: -* S3 or S3-compatible stores, like MinIO +* S3 or S3-compatible stores, like MinIO or Ceph Rados * Microsoft Azure Blob Storage * Google Cloud Storage @@ -102,8 +102,8 @@ backups: ``` Each backup adapter takes it's own set of parameters, listed in the [Configuration options](#Configuration-options) section -below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, -`backup.azure`, or `backup.google`. +below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: +`backups.objectStorage.providerSettings.s3`, `backups.objectStorage.providerSettings.azure` or `backups.objectStorage.providerSettings.google`. Recovery diff --git a/charts/cluster/docs/Getting Started.md b/charts/cluster/docs/Getting Started.md index 54dad419d..e2dae60d3 100644 --- a/charts/cluster/docs/Getting Started.md +++ b/charts/cluster/docs/Getting Started.md @@ -48,10 +48,10 @@ Most importantly you should configure your backup storage. CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are -stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following -providers are supported: +stored in the specified location. The backup provider is configured via the `backups.objectStorage.provider` parameter. +The following providers are supported: -* S3 or S3-compatible stores, like MinIO +* S3 or S3-compatible stores, like MinIO or Ceph Rados * Microsoft Azure Blob Storage * Google Cloud Storage @@ -67,8 +67,8 @@ Additionally you can specify the following parameters: ``` Each backup adapter takes it's own set of parameters, listed in the [Configuration options](../README.md#Configuration-options) section -below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, -`backup.azure`, or `backup.google`. +below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: +`backups.objectStorage.providerSettings.s3`, `backups.objectStorage.providerSettings.azure` or `backups.objectStorage.providerSettings.google`. ### Cluster configuration diff --git a/charts/cluster/docs/Recovery.md b/charts/cluster/docs/Recovery.md index 1a7a9153c..275f8ceec 100644 --- a/charts/cluster/docs/Recovery.md +++ b/charts/cluster/docs/Recovery.md @@ -7,21 +7,23 @@ CNPG does not support recovery in-place. Instead you need to create a new cluste You can find more information about the recovery process in the [CNPG documentation](https://cloudnative-pg.io/documentation/current/backup_recovery). -There are 3 types of recovery possible with CNPG: +There are 4 types of recovery possible with CNPG: * Recovery from a backup object in the same Kubernetes namespace. +* Recovery from a volume snapshot in the same Kubernetes namespace, if supported by the CSI provider. * Recovery from a Barman Object Store, that could be located anywhere. * Streaming replication from an operating cluster using `pg_basebackup`. When performing a recovery you are strongly advised to use the same configuration and PostgreSQL version as the original cluster. +Recovering from older version of PostgreSQL is not posible, but it's possible to use [import](https://cloudnative-pg.io/documentation/current/database_import/) instead. To begin, create a `values.yaml` that contains the following: 1. Set `mode: recovery` to indicate that you want to perform bootstrap the new cluster from an existing one. -2. Set the `recovery.method` to the type of recovery you want to perform. -3. Set either the `recovery.backupName` or the Barman Object Store configuration - i.e. `recovery.provider` and appropriate S3, Azure or GCS configuration. In case of `pg_basebackup` complete the `recovery.pgBaseBackup` section. -4. Optionally set the `recovery.pitrTarget.time` in RFC3339 format to perform a point-in-time recovery (not applicable for `pgBaseBackup`). -5. Retain the identical PostgreSQL version and configuration as the original cluster. -6. Make sure you don't use the same backup section name as the original cluster. We advise you change the `path` within the storage location if you want to reuse the same storage location/bucket. +2. Set the `recovery.method` to the type of recovery you want to perform. Supported methods are listed under `recovery.methodSettings`. +3. Configure `recovery.methodSettings` for selected `recovery.method`. +4. Optionally set the `recovery.pitrTarget.time` in RFC3339 format to perform a point-in-time recovery (supported with `backup`, `objectStorage` and `volumeSnapshot`). +5. Retain the identical major PostgreSQL version and same/newer minor version as on the original cluster. +6. **Important**: make sure you don't use the same backup section name as the original cluster. We advise you change the `path` within the storage location if you want to reuse the same storage location/bucket. One pattern is adding a version number at the end of the path, e.g. `/v1` or `/v2` after each recovery procedure. Example recovery configurations can be found in the [examples](../examples) directory. diff --git a/charts/cluster/examples/basic.yaml b/charts/cluster/examples/basic.yaml index 5b608c267..7f4d98023 100644 --- a/charts/cluster/examples/basic.yaml +++ b/charts/cluster/examples/basic.yaml @@ -1,5 +1,4 @@ mode: standalone + cluster: instances: 1 -backups: - enabled: false diff --git a/charts/cluster/examples/custom-queries.yaml b/charts/cluster/examples/custom-queries.yaml index 7995202d8..bb6e41f61 100644 --- a/charts/cluster/examples/custom-queries.yaml +++ b/charts/cluster/examples/custom-queries.yaml @@ -1,4 +1,5 @@ type: postgresql + mode: standalone cluster: @@ -19,6 +20,3 @@ cluster: - ratio: usage: GAUGE description: "Cache hit ratio" - -backups: - enabled: false diff --git a/charts/cluster/examples/import-microservice.yaml b/charts/cluster/examples/import-microservice.yaml new file mode 100644 index 000000000..461e2ea85 --- /dev/null +++ b/charts/cluster/examples/import-microservice.yaml @@ -0,0 +1,23 @@ +mode: import + +cluster: + instances: 1 + +import: + type: microservice + typeSettings: + microservice: + database: source-db + +recovery: + method: pgBasebackup + methodSettings: + pgBasebackup: + connectionParameters: + host: source-db.foo.com + user: postgres + sslMode: require + auth: password + authDetails: + password: |- + superuser-password diff --git a/charts/cluster/examples/import-monolith-full.yaml b/charts/cluster/examples/import-monolith-full.yaml new file mode 100644 index 000000000..3fd4ad83e --- /dev/null +++ b/charts/cluster/examples/import-monolith-full.yaml @@ -0,0 +1,26 @@ +mode: import + +cluster: + instances: 1 + +import: + type: monolith + typeSettings: + monolith: + databases: + - * + roles: + - * + +recovery: + method: pgBasebackup + methodSettings: + pgBasebackup: + connectionParameters: + host: source-db.foo.com + user: postgres + sslMode: require + auth: password + authDetails: + password: |- + superuser-password diff --git a/charts/cluster/examples/import-monolith.yaml b/charts/cluster/examples/import-monolith.yaml new file mode 100644 index 000000000..da2c5b992 --- /dev/null +++ b/charts/cluster/examples/import-monolith.yaml @@ -0,0 +1,29 @@ +mode: import + +cluster: + instances: 1 + +import: + type: monolith + typeSettings: + monolith: + databases: + - db1 + - db2 + - db3 + roles: + - role1 + - role2 + +recovery: + method: pgBasebackup + methodSettings: + pgBasebackup: + connectionParameters: + host: source-db.foo.com + user: postgres + sslMode: require + auth: password + authDetails: + password: |- + superuser-password diff --git a/charts/cluster/examples/pgbouncer.yaml b/charts/cluster/examples/pgbouncer.yaml index 1da966275..c32c95cb1 100644 --- a/charts/cluster/examples/pgbouncer.yaml +++ b/charts/cluster/examples/pgbouncer.yaml @@ -1,8 +1,8 @@ mode: standalone + cluster: instances: 1 -backups: - enabled: false + pooler: enabled: true instances: 1 diff --git a/charts/cluster/examples/postgis.yaml b/charts/cluster/examples/postgis.yaml index 6c686dc62..a43d066c6 100644 --- a/charts/cluster/examples/postgis.yaml +++ b/charts/cluster/examples/postgis.yaml @@ -1,6 +1,6 @@ type: postgis + mode: standalone + cluster: instances: 1 -backups: - enabled: false \ No newline at end of file diff --git a/charts/cluster/examples/recovery-backup.yaml b/charts/cluster/examples/recovery-backup.yaml index d11187f5c..c2ecfce6b 100644 --- a/charts/cluster/examples/recovery-backup.yaml +++ b/charts/cluster/examples/recovery-backup.yaml @@ -1,22 +1,26 @@ mode: recovery -recovery: - method: backup - backupName: "database-clustermarket-database-daily-backup-1683244800" - cluster: instances: 1 +recovery: + method: backup + methodSettings: + backup: + name: database-clustermarket-database-daily-backup-1683244800 + backups: - provider: s3 - s3: - region: "eu-west-1" - bucket: "db-backups" - path: "/v1-restore" - accessKey: "AWS_S3_ACCESS_KEY" - secretKey: "AWS_S3_SECRET_KEY" + objectStorage: + provider: s3 + providerSettings: + s3: + region: eu-west-1 + bucket: db-backups + path: /v1-restore + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" scheduledBackups: - name: daily-backup # Daily at midnight schedule: "0 0 0 * * *" # Daily at midnight backupOwnerReference: self - retentionPolicy: "30d" \ No newline at end of file + retentionPolicy: 30d diff --git a/charts/cluster/examples/recovery-object_store-aws.yaml b/charts/cluster/examples/recovery-object_store-aws.yaml new file mode 100644 index 000000000..9eb82e7fc --- /dev/null +++ b/charts/cluster/examples/recovery-object_store-aws.yaml @@ -0,0 +1,33 @@ +mode: recovery + +cluster: + instances: 1 + +recovery: + method: objectStorage + methodSettings: + objectStorage: + clusterName: cluster-name-to-recover-from + provider: s3 + s3: + region: eu-west-1 + bucket: db-backups + path: /v1-restore + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + +backups: + objectStorage: + provider: s3 + providerSettings: + s3: + region: eu-west-1 + bucket: db-backups + path: /v2-restore + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + scheduledBackups: + - name: daily-backup # Daily at midnight + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self + retentionPolicy: 30d diff --git a/charts/cluster/examples/recovery-object_store-minio.yaml b/charts/cluster/examples/recovery-object_store-minio.yaml new file mode 100644 index 000000000..10a98dbd2 --- /dev/null +++ b/charts/cluster/examples/recovery-object_store-minio.yaml @@ -0,0 +1,40 @@ +mode: recovery + +cluster: + instances: 1 + +recovery: + method: objectStorage + methodSettings: + objectStorage: + clusterName: standalone-cluster + endpointURL: https://minio.minio.svc.cluster.local + endpointCA: + name: kube-root-ca.crt + key: ca.crt + provider: s3 + s3: + bucket: mybucket + path: /v1 + accessKey: minio + secretKey: minio123 + +backups: + objectStorage: + provider: s3 + providerSettings: + endpointURL: https://minio.minio.svc.cluster.local + endpointCA: + name: kube-root-ca.crt + key: ca.crt + s3: + bucket: mybucket + path: /v1 + accessKey: minio + secretKey: minio123 + wal: + encryption: "" + data: + encryption: "" + scheduledBackups: [] + retentionPolicy: 30d diff --git a/charts/cluster/examples/recovery-object_store.yaml b/charts/cluster/examples/recovery-object_store.yaml deleted file mode 100644 index 742d5341c..000000000 --- a/charts/cluster/examples/recovery-object_store.yaml +++ /dev/null @@ -1,30 +0,0 @@ -mode: recovery - -recovery: - method: object_store - clusterName: "cluster-name-to-recover-from" - provider: s3 - s3: - region: "eu-west-1" - bucket: "db-backups" - path: "/v1-restore" - accessKey: "AWS_S3_ACCESS_KEY" - secretKey: "AWS_S3_SECRET_KEY" - -cluster: - instances: 1 - -backups: - endpointURL: "https://cm-db-chart-test.ams3.digitaloceanspaces.com" - provider: s3 - s3: - region: "eu-west-1" - bucket: "db-backups" - path: "/v1-restore" - accessKey: "AWS_S3_ACCESS_KEY" - secretKey: "AWS_S3_SECRET_KEY" - scheduledBackups: - - name: daily-backup # Daily at midnight - schedule: "0 0 0 * * *" # Daily at midnight - backupOwnerReference: self - retentionPolicy: "30d" diff --git a/charts/cluster/examples/recovery-pg_basebackup-password.yaml b/charts/cluster/examples/recovery-pg_basebackup-password.yaml new file mode 100644 index 000000000..e995156c8 --- /dev/null +++ b/charts/cluster/examples/recovery-pg_basebackup-password.yaml @@ -0,0 +1,17 @@ +mode: recovery + +cluster: + instances: 1 + +recovery: + method: pgBasebackup + methodSettings: + pgBasebackup: + connectionParameters: + host: source-db.foo.com + user: streaming_replica + sslMode: require + auth: password + authDetails: + password: |- + replication-password diff --git a/charts/cluster/examples/recovery-pg_basebackup-tls.yaml b/charts/cluster/examples/recovery-pg_basebackup-tls.yaml new file mode 100644 index 000000000..d190be4fd --- /dev/null +++ b/charts/cluster/examples/recovery-pg_basebackup-tls.yaml @@ -0,0 +1,25 @@ +mode: recovery + +cluster: + instances: 1 + +recovery: + method: pgBasebackup + methodSettings: + pgBasebackup: + connectionParameters: + host: source-db.foo.com + user: streaming_replica + sslMode: verify-ca + auth: tls + authDetails: + tls: + key: |- + -----BEGIN PRIVATE KEY----- + -----END PRIVATE KEY----- + crt: |- + -----BEGIN CERTIFICATE----- + -----END CERTIFICATE----- + ca: |- + -----BEGIN CERTIFICATE----- + -----END CERTIFICATE----- diff --git a/charts/cluster/examples/recovery-pg_basebackup.yaml b/charts/cluster/examples/recovery-pg_basebackup.yaml deleted file mode 100644 index ef77857a3..000000000 --- a/charts/cluster/examples/recovery-pg_basebackup.yaml +++ /dev/null @@ -1,14 +0,0 @@ -mode: "recovery" - -recovery: - method: "pg_basebackup" - pgBaseBackup: - sourceHost: "source-db.foo.com" - sourceUsername: "streaming_replica" - existingPasswordSecret: "source-db-replica-password" - -cluster: - instances: 1 - -backups: - enabled: false \ No newline at end of file diff --git a/charts/cluster/examples/recovery-volume_snapshot.yaml b/charts/cluster/examples/recovery-volume_snapshot.yaml new file mode 100644 index 000000000..e076168c6 --- /dev/null +++ b/charts/cluster/examples/recovery-volume_snapshot.yaml @@ -0,0 +1,21 @@ +mode: recovery + +cluster: + instances: 1 + +recovery: + method: volumeSnapshot + methodSettings: + volumeSnapshot: + storageSnapshotName: database-clustermarket-database-snapshot + walSnapshotName: wal-clustermarket-database-snapshot + +backups: + volumeSnapshot: + className: csi-snapshot-class + walSnapshotName: csi-snapshot-class + scheduledBackups: + - name: hourly-snapshot + schedule: "0 0 * * * *" + backupOwnerReference: self + method: volumeSnapshot diff --git a/charts/cluster/examples/replica-distributed-primary.yaml b/charts/cluster/examples/replica-distributed-primary.yaml new file mode 100644 index 000000000..87a8b9134 --- /dev/null +++ b/charts/cluster/examples/replica-distributed-primary.yaml @@ -0,0 +1,37 @@ +mode: replica + +cluster: + instances: 1 + +replica: + topology: distributed + topologySettings: + distributed: + primary: true + +recovery: + method: objectStorage + clusterName: database-clustermarket-euc1 + provider: s3 + s3: + region: eu-central-1 + bucket: euc1-db-backups + path: /v1-restore + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + +backups: + objectStorage: + provider: s3 + providerSettings: + s3: + region: eu-west-1 + bucket: euw1-db-backups + path: /v1-restore + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + scheduledBackups: + - name: daily-backup # Daily at midnight + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self + retentionPolicy: 30d diff --git a/charts/cluster/examples/replica-distributed-replica.yaml b/charts/cluster/examples/replica-distributed-replica.yaml new file mode 100644 index 000000000..21a02d3d1 --- /dev/null +++ b/charts/cluster/examples/replica-distributed-replica.yaml @@ -0,0 +1,37 @@ +mode: replica + +cluster: + instances: 1 + +replica: + topology: distributed + topologySettings: + distributed: + primary: false + +recovery: + method: objectStorage + clusterName: database-clustermarket-euw1 + provider: s3 + s3: + region: eu-west-1 + bucket: euw1-db-backups + path: /v1-restore + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + +backups: + objectStorage: + provider: s3 + providerSettings: + s3: + region: eu-central-1 + bucket: euc1-db-backups + path: /v1-restore + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + scheduledBackups: + - name: daily-backup # Daily at midnight + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self + retentionPolicy: 30d diff --git a/charts/cluster/examples/replica-standalone.yaml b/charts/cluster/examples/replica-standalone.yaml new file mode 100644 index 000000000..831ae1879 --- /dev/null +++ b/charts/cluster/examples/replica-standalone.yaml @@ -0,0 +1,20 @@ +mode: replica + +cluster: + instances: 1 + +replica: + topology: standalone + +recovery: + method: pgBasebackup + methodSettings: + pgBasebackup: + connectionParameters: + host: source-db.foo.com + user: streaming_replica + sslMode: require + auth: password + authDetails: + password: |- + replication-password diff --git a/charts/cluster/examples/standalone-s3.yaml b/charts/cluster/examples/standalone-s3.yaml index bf1794d06..7a09784e2 100644 --- a/charts/cluster/examples/standalone-s3.yaml +++ b/charts/cluster/examples/standalone-s3.yaml @@ -4,16 +4,17 @@ cluster: instances: 1 backups: - enabled: true - provider: s3 - s3: - region: "eu-west-1" - bucket: "db-backups" - path: "/v1" - accessKey: "AWS_S3_ACCESS_KEY" - secretKey: "AWS_S3_SECRET_KEY" + objectStorage: + provider: s3 + providerSettings: + s3: + region: eu-west-1 + bucket: db-backups + path: /v1 + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" scheduledBackups: - name: daily-backup # Daily at midnight schedule: "0 0 0 * * *" # Daily at midnight backupOwnerReference: self - retentionPolicy: "30d" + retentionPolicy: 30d diff --git a/charts/cluster/templates/NOTES.txt b/charts/cluster/templates/NOTES.txt index ba44e95df..95b29382d 100644 --- a/charts/cluster/templates/NOTES.txt +++ b/charts/cluster/templates/NOTES.txt @@ -45,37 +45,31 @@ Configuration {{- $scheduledBackups = "None" -}} {{- end -}} -{{- $mode := .Values.mode -}} {{- $source := "" -}} -{{- if eq .Values.mode "recovery" }} -{{- $mode = printf "%s (%s)" .Values.mode .Values.recovery.method -}} - {{- if eq .Values.recovery.method "pg_basebackup" }} - {{- $source = printf "postgresql://%s@%s:%.0f/%s" .Values.recovery.pgBaseBackup.source.username .Values.recovery.pgBaseBackup.source.host .Values.recovery.pgBaseBackup.source.port .Values.recovery.pgBaseBackup.source.database -}} - {{- end -}} +{{- if (eq (include "cluster.recovery.method.pgBasebackup.enabled" .) "true") }} + {{- $source = printf "postgresql://%s@%s:%.0f/%s" .Values.recovery.methodSettings.pgBasebackup.connectionParameters.username .Values.recovery.methodSettings.pgBasebackup.connectionParameters.host .Values.recovery.methodSettings.pgBasebackup.connectionParameters.port .Values.recovery.methodSettings.pgBasebackup.connectionParameters.database -}} {{- end -}} ╭───────────────────┬──────────────────────────────────────────────────────────╮ │ Configuration │ Value │ ┝━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥ -│ Cluster mode │ {{ printf "%-56s" $mode }} │ -│ Type │ {{ printf "%-56s" .Values.type }} │ +│ Cluster mode │ {{ (printf "%-56s" .Values.mode) }} │ +│ Type │ {{ (printf "%-56s" .Values.type) }} │ │ Image │ {{ include "cluster.color-info" (printf "%-56s" (include "cluster.imageName" .)) }} │ -{{- if eq .Values.mode "recovery" }} +{{- if (eq (include "cluster.recovery.method.pgBasebackup.enabled" .) "true") }} │ Source │ {{ printf "%-56s" $source }} │ {{- end }} -│ Instances │ {{ include (printf "%s%s" "cluster.color-" $redundancyColor) (printf "%-56s" (toString .Values.cluster.instances)) }} │ -│ Backups │ {{ include (printf "%s%s" "cluster.color-" (ternary "ok" "error" .Values.backups.enabled)) (printf "%-56s" (ternary "Enabled" "Disabled" .Values.backups.enabled)) }} │ -{{- if .Values.backups.enabled }} -│ Backup Provider │ {{ printf "%-56s" (title .Values.backups.provider) }} │ -│ Scheduled Backups │ {{ printf "%-56s" $scheduledBackups }} │ -{{- end }} -│ Storage │ {{ printf "%-56s" .Values.cluster.storage.size }} │ -│ Storage Class │ {{ printf "%-56s" (default "Default" .Values.cluster.storage.storageClass) }} │ -│ PGBouncer │ {{ printf "%-56s" (ternary "Enabled" "Disabled" .Values.pooler.enabled) }} │ -│ Monitoring │ {{ include (printf "%s%s" "cluster.color-" (ternary "ok" "error" .Values.cluster.monitoring.enabled)) (printf "%-56s" (ternary "Enabled" "Disabled" .Values.cluster.monitoring.enabled)) }} │ -╰───────────────────┴──────────────────────────────────────────────────────────╯ +│ Instances │ {{ include (printf "%s%s" "cluster.color-" $redundancyColor) (printf "%-54s" (toString .Values.cluster.instances)) }} │ +│ Backups │ {{ include (printf "%s%s" "cluster.color-" (ternary "ok" "error" (eq (include "cluster.backups.enabled" .) "true"))) (printf "%-54s" (ternary "Enabled" "Disabled" (eq (include "cluster.backups.enabled" .) "true"))) }} │ +│ Backup Provider │ {{ (printf "%-56s" (title .Values.backups.objectStorage.provider)) }} │ +│ Scheduled Backups │ {{ (printf "%-56s" $scheduledBackups) }} │ +│ Storage │ {{ (printf "%-56s" .Values.cluster.storage.size) }} │ +│ Storage Class │ {{ (printf "%-56s" (default "Default" .Values.cluster.storage.storageClass)) }} │ +│ PGBouncer │ {{ (printf "%-56s" (ternary "Enabled" "Disabled" .Values.pooler.enabled)) }} │ +│ Monitoring │ {{ include (printf "%s%s" "cluster.color-" (ternary "ok" "error" .Values.cluster.monitoring.enabled)) (printf "%-54s" (ternary "Enabled" "Disabled" .Values.cluster.monitoring.enabled)) }} │ +╰───────────────────┴────────────────────────────────────────────────────────╯ -{{ if not .Values.backups.enabled }} +{{ if ne (include "cluster.backups.enabled" .) "true" }} {{- include "cluster.color-error" "Warning! Backups not enabled. Recovery will not be possible! Do not use this configuration in production.\n" }} {{ end -}} @@ -84,3 +78,7 @@ Configuration {{- else if lt (int .Values.cluster.instances) 3 -}} {{- include "cluster.color-warning" "Warning! Single instance redundancy available only. Instance failure will put the cluster at risk.\n" }} {{ end -}} + +{{ if or (and (eq (include "cluster.recovery.enabled" .) "true") (not (empty .Values.recovery.existingSecret))) (and (eq (include "cluster.backups.enabled" .) "true") (not (empty .Values.backups.existingSecret))) }} + {{- include "cluster.color-info" "Existing secrets are used, make sure they have been created with all the necessary keys\n" }} +{{ end -}} diff --git a/charts/cluster/templates/_backup.tpl b/charts/cluster/templates/_backup.tpl index 8059618c4..5489e1df7 100644 --- a/charts/cluster/templates/_backup.tpl +++ b/charts/cluster/templates/_backup.tpl @@ -1,19 +1,34 @@ {{- define "cluster.backup" -}} -{{- if .Values.backups.enabled }} +{{- if (eq (include "cluster.backups.enabled" .) "true") }} backup: - target: "prefer-standby" + target: {{ .Values.backups.target }} retentionPolicy: {{ .Values.backups.retentionPolicy }} + {{- if (eq (include "cluster.backups.objectStorage.enabled" .) "true") }} barmanObjectStore: wal: - compression: {{ .Values.backups.wal.compression }} - encryption: {{ .Values.backups.wal.encryption }} - maxParallel: {{ .Values.backups.wal.maxParallel }} + compression: {{ .Values.backups.objectStorage.wal.compression }} + encryption: {{ .Values.backups.objectStorage.wal.encryption }} + maxParallel: {{ .Values.backups.objectStorage.wal.maxParallel }} data: - compression: {{ .Values.backups.data.compression }} - encryption: {{ .Values.backups.data.encryption }} - jobs: {{ .Values.backups.data.jobs }} + compression: {{ .Values.backups.objectStorage.data.compression }} + encryption: {{ .Values.backups.objectStorage.data.encryption }} + jobs: {{ .Values.backups.objectStorage.data.jobs }} - {{- $d := dict "chartFullname" (include "cluster.fullname" .) "scope" .Values.backups "secretPrefix" "backup" }} + {{- $d := dict "chartFullname" (include "cluster.fullname" .) "scope" .Values.backups.objectStorage "secretPrefix" "backup" "existingSecret" .Values.backups.existingSecret }} {{- include "cluster.barmanObjectStoreConfig" $d | nindent 2 }} + {{- end }} + {{- if (not (empty .Values.backups.volumeSnapshot.className )) }} + {{- with .Values.backups.volumeSnapshot }} + volumeSnapshot: + className: {{ .className }} + {{- if (not (empty .walClassName)) }} + walClassName: {{ .walClassName }} + {{- end }} + online: {{ .online }} + onlineConfiguration: + immediateCheckpoint: {{ .onlineConfiguration.immediateCheckpoint }} + waitForArchive: {{ .onlineConfiguration.waitForArchive }} + {{- end }} + {{- end }} {{- end }} {{- end }} diff --git a/charts/cluster/templates/_barman_object_store.tpl b/charts/cluster/templates/_barman_object_store.tpl index 881047655..6dc615ed8 100644 --- a/charts/cluster/templates/_barman_object_store.tpl +++ b/charts/cluster/templates/_barman_object_store.tpl @@ -16,12 +16,12 @@ {{- if eq .scope.provider "s3" }} {{- if empty .scope.endpointURL }} - endpointURL: "https://s3.{{ required "You need to specify S3 region if endpointURL is not specified." .scope.s3.region }}.amazonaws.com" + endpointURL: "https://s3.{{ required "You need to specify S3 region if endpointURL is not specified." .scope.providerSettings.s3.region }}.amazonaws.com" {{- end }} {{- if empty .scope.destinationPath }} - destinationPath: "s3://{{ required "You need to specify S3 bucket if destinationPath is not specified." .scope.s3.bucket }}{{ .scope.s3.path }}" + destinationPath: "s3://{{ required "You need to specify S3 bucket if destinationPath is not specified." .scope.providerSettings.s3.bucket }}{{ .scope.providerSettings.s3.path }}" {{- end }} - {{- $secretName := coalesce .scope.secret.name (printf "%s-%s-s3-creds" .chartFullname .secretPrefix) }} + {{- $secretName := coalesce .existingSecret.name (printf "%s-%s-s3-creds" .chartFullname .secretPrefix) }} s3Credentials: accessKeyId: name: {{ $secretName }} @@ -31,13 +31,13 @@ key: ACCESS_SECRET_KEY {{- else if eq .scope.provider "azure" }} {{- if empty .scope.destinationPath }} - destinationPath: "https://{{ required "You need to specify Azure storageAccount if destinationPath is not specified." .scope.azure.storageAccount }}.{{ .scope.azure.serviceName }}.core.windows.net/{{ .scope.azure.containerName }}{{ .scope.azure.path }}" + destinationPath: "https://{{ required "You need to specify Azure storageAccount if destinationPath is not specified." .scope.providerSettings.azure.storageAccount }}.{{ .scope.providerSettings.azure.serviceName }}.core.windows.net/{{ .scope.providerSettings.azure.containerName }}{{ .scope.providerSettings.azure.path }}" {{- end }} - {{- $secretName := coalesce .scope.secret.name (printf "%s-%s-azure-creds" .chartFullname .secretPrefix) }} + {{- $secretName := coalesce .existingSecret.name (printf "%s-%s-azure-creds" .chartFullname .secretPrefix) }} azureCredentials: - {{- if .scope.azure.inheritFromAzureAD }} + {{- if .scope.providerSettings.azure.inheritFromAzureAD }} inheritFromAzureAD: true - {{- else if .scope.azure.connectionString }} + {{- else if .scope.providerSettings.azure.connectionString }} connectionString: name: {{ $secretName }} key: AZURE_CONNECTION_STRING @@ -45,7 +45,7 @@ storageAccount: name: {{ $secretName }} key: AZURE_STORAGE_ACCOUNT - {{- if .scope.azure.storageKey }} + {{- if .scope.providerSettings.azure.storageKey }} storageKey: name: {{ $secretName }} key: AZURE_STORAGE_KEY @@ -57,15 +57,15 @@ {{- end }} {{- else if eq .scope.provider "google" }} {{- if empty .scope.destinationPath }} - destinationPath: "gs://{{ required "You need to specify Google storage bucket if destinationPath is not specified." .scope.google.bucket }}{{ .scope.google.path }}" + destinationPath: "gs://{{ required "You need to specify Google storage bucket if destinationPath is not specified." .scope.providerSettings.google.bucket }}{{ .scope.providerSettings.google.path }}" {{- end }} - {{- $secretName := coalesce .scope.secret.name (printf "%s-%s-google-creds" .chartFullname .secretPrefix) }} + {{- $secretName := coalesce .existingSecret.name (printf "%s-%s-google-creds" .chartFullname .secretPrefix) }} googleCredentials: - gkeEnvironment: {{ .scope.google.gkeEnvironment }} -{{- if not .scope.google.gkeEnvironment }} + gkeEnvironment: {{ .scope.providerSettings.google.gkeEnvironment }} +{{- if not .scope.providerSettings.google.gkeEnvironment }} applicationCredentials: name: {{ $secretName }} key: APPLICATION_CREDENTIALS {{- end }} -{{- end -}} +{{- end }} {{- end -}} diff --git a/charts/cluster/templates/_bootstrap.tpl b/charts/cluster/templates/_bootstrap.tpl index 81665d2e2..e12791e3d 100644 --- a/charts/cluster/templates/_bootstrap.tpl +++ b/charts/cluster/templates/_bootstrap.tpl @@ -4,7 +4,7 @@ bootstrap: initdb: {{- with .Values.cluster.initdb }} {{- with (omit . "postInitApplicationSQL") }} - {{- . | toYaml | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} {{- end }} postInitApplicationSQL: @@ -19,74 +19,147 @@ bootstrap: {{- with .Values.cluster.initdb }} {{- range .postInitApplicationSQL }} {{- printf "- %s" . | nindent 6 }} - {{- end -}} - {{- end -}} -{{- else if eq .Values.mode "recovery" -}} + {{- end }} + {{- end }} +{{- else if (eq (include "cluster.recovery.enabled" .) "true") }} bootstrap: -{{- if eq .Values.recovery.method "pg_basebackup" }} + {{- if (eq (include "cluster.import.enabled" .) "true") }} + initdb: + {{- if and (eq (include "cluster.import.type.microservice.enabled" .) "true") }} + {{- with .Values.import.typeSettings.microservice.owner }} + owner: {{ . }} + {{- end }} + {{- end }} + import: + {{- if (eq (include "cluster.import.type.microservice.enabled" .) "true") }} + type: microservice + databases: + - {{ .Values.import.typeSettings.microservice.database }} + {{- with .Values.import.typeSettings.microservice.postImportApplicationSQL }} + postImportApplicationSQL: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- else if (eq (include "cluster.import.type.monolith.enabled" .) "true") }} + type: monolith + {{- with .Values.import.typeSettings.monolith.databases }} + databases: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.import.typeSettings.monolith.roles }} + roles: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + source: + externalCluster: pgBasebackupRecoveryCluster + {{- else if eq .Values.recovery.method "pgBasebackup" }} pg_basebackup: - source: pgBaseBackupSource - {{ with .Values.recovery.pgBaseBackup.database }} + source: pgBasebackupRecoveryCluster + {{- if and (eq .Values.mode "recovery") (not (empty .Values.recovery.methodSettings.pgBasebackup.database)) }} + {{- with .Values.recovery.methodSettings.pgBasebackup.database }} database: {{ . }} {{- end }} - {{ with .Values.recovery.pgBaseBackup.owner }} + {{- with .Values.recovery.methodSettings.pgBasebackup.owner }} owner: {{ . }} {{- end }} - {{ with .Values.recovery.pgBaseBackup.secret }} + {{- with .Values.recovery.methodSettings.pgBasebackup.ownerSecret }} secret: - {{- toYaml . | nindent 6 }} + name: {{ . }} {{- end }} - -externalClusters: -- name: pgBaseBackupSource - connectionParameters: - host: {{ .Values.recovery.pgBaseBackup.source.host | quote }} - port: {{ .Values.recovery.pgBaseBackup.source.port | quote }} - user: {{ .Values.recovery.pgBaseBackup.source.username | quote }} - dbname: {{ .Values.recovery.pgBaseBackup.source.database | quote }} - sslmode: {{ .Values.recovery.pgBaseBackup.source.sslMode | quote }} - {{- if .Values.recovery.pgBaseBackup.source.passwordSecret.name }} - password: - name: {{ default (printf "%s-pg-basebackup-password" (include "cluster.fullname" .)) .Values.recovery.pgBaseBackup.source.passwordSecret.name }} - key: {{ .Values.recovery.pgBaseBackup.source.passwordSecret.key }} - {{- end }} - {{- if .Values.recovery.pgBaseBackup.source.sslKeySecret.name }} - sslKey: - name: {{ .Values.recovery.pgBaseBackup.source.sslKeySecret.name }} - key: {{ .Values.recovery.pgBaseBackup.source.sslKeySecret.key }} - {{- end }} - {{- if .Values.recovery.pgBaseBackup.source.sslCertSecret.name }} - sslCert: - name: {{ .Values.recovery.pgBaseBackup.source.sslCertSecret.name }} - key: {{ .Values.recovery.pgBaseBackup.source.sslCertSecret.key }} {{- end }} - {{- if .Values.recovery.pgBaseBackup.source.sslRootCertSecret.name }} - sslRootCert: - name: {{ .Values.recovery.pgBaseBackup.source.sslRootCertSecret.name }} - key: {{ .Values.recovery.pgBaseBackup.source.sslRootCertSecret.key }} - {{- end }} - -{{- else }} + {{- else }} recovery: + {{- if and (eq .Values.mode "recovery") (has .Values.recovery.method (list "backup" "objectStorage" "volumeSnapshot")) }} {{- with .Values.recovery.pitrTarget.time }} recoveryTarget: targetTime: {{ . }} {{- end }} + {{- end }} {{- if eq .Values.recovery.method "backup" }} backup: - name: {{ .Values.recovery.backupName }} - {{- else if eq .Values.recovery.method "object_store" }} + name: {{ required ".Values.recovery.methodSettings.backup.name is required, but not specified." .Values.recovery.methodSettings.backup.name }} + {{- else if eq .Values.recovery.method "objectStorage" }} source: objectStoreRecoveryCluster + {{- else if eq .Values.recovery.method "volumeSnapshot" }} + source: volumeSnapshotRecoveryCluster + volumeSnapshots: + storage: + apiGroup: snapshot.storage.k8s.io + kind: VolumeSnapshot + name: {{ required ".Values.recovery.methodSettings.volumeSnapshot.storageSnapshotName is required, but not specified." .Values.recovery.methodSettings.volumeSnapshot.storageSnapshotName }} + {{- with .Values.recovery.methodSettings.volumeSnapshot.walSnapshotName }} + walStorage: + apiGroup: snapshot.storage.k8s.io + kind: VolumeSnapshot + name: {{ . }} + {{- end }} {{- end }} - + {{- end }} +{{ if (eq (include "cluster.replica.enabled" .) "true") }} +replica: + {{- if (eq (include "cluster.replica.topology.standalone.enabled" .) "true") }} + enabled: true + {{- if not (empty .Values.replica.topologySettings.minApplyDelay) }} + minApplyDelay: {{ .Values.replica.topologySettings.minApplyDelay }} + {{- end }} + {{- else if (eq (include "cluster.replica.topology.distributed.enabled" .) "true") }} + {{- if .Values.replica.topologySettings.distributed.primary }} + primary: {{ include "cluster.fullname" . }} + {{- else }} + primary: {{ include "cluster.replica.source" . }} + {{- end }} + {{- end }} + source: {{ include "cluster.replica.source" . }} +{{- end }} +{{ if eq .Values.recovery.method "objectStorage" }} externalClusters: - - name: objectStoreRecoveryCluster +{{- if eq .Values.replica.topology "distributed" }} + - name: {{ include "cluster.fullname" . }} barmanObjectStore: - serverName: {{ .Values.recovery.clusterName }} - {{- $d := dict "chartFullname" (include "cluster.fullname" .) "scope" .Values.recovery "secretPrefix" "recovery" -}} + serverName: {{ include "cluster.fullname" . }} + {{- $d := dict "chartFullname" (include "cluster.fullname" .) "scope" .Values.backups.objectStorage "secretPrefix" "backup" "existingSecret" .Values.backups.existingSecret }} {{- include "cluster.barmanObjectStoreConfig" $d | nindent 4 }} {{- end }} -{{- else }} - {{ fail "Invalid cluster mode!" }} + - name: objectStoreRecoveryCluster + barmanObjectStore: + serverName: {{ default (include "cluster.fullname" .) .Values.recovery.methodSettings.objectStorage.clusterName }} + {{- $d := dict "chartFullname" (include "cluster.fullname" .) "scope" .Values.recovery.methodSettings.objectStorage "secretPrefix" "recovery" "existingSecret" .Values.recovery.existingSecret }} + {{- include "cluster.barmanObjectStoreConfig" $d | nindent 4 }} +{{- else if eq .Values.recovery.method "pgBasebackup" }} +externalClusters: + - name: pgBasebackupRecoveryCluster + connectionParameters: + host: {{ required ".Values.recovery.methodSettings.pgBasebackup.connectionParameters.host is required, but not specified." .Values.recovery.methodSettings.pgBasebackup.connectionParameters.host }} + port: {{ required ".Values.recovery.methodSettings.pgBasebackup.connectionParameters.port is required, but not specified." (.Values.recovery.methodSettings.pgBasebackup.connectionParameters.port | quote) }} + user: {{ required ".Values.recovery.methodSettings.pgBasebackup.connectionParameters.user is required, but not specified." .Values.recovery.methodSettings.pgBasebackup.connectionParameters.user }} + {{- with .Values.recovery.methodSettings.pgBasebackup.connectionParameters.sslMode }} + sslmode: {{ . }} + {{- end }} + {{- if and (eq .Values.mode "recovery") (not (empty .Values.recovery.methodSettings.pgBasebackup.database)) }} + dbname: {{ default .Values.recovery.methodSettings.pgBasebackup.database .Values.recovery.methodSettings.pgBasebackup.connectionParameters.database }} + {{- else if or (eq .Values.mode "replica") (eq .Values.mode "import") }} + dbname: postgres + {{- end }} + {{- $secretName := coalesce .Values.recovery.existingSecret.name (printf "%s-recovery-pgbb-creds" (include "cluster.fullname" .)) }} + {{- if eq .Values.recovery.methodSettings.auth "password" }} + password: + {{- if .Values.recovery.methodSettings.pgBasebackup.sourcePassword }} + name: {{ printf $secretName }} + {{- end }} + key: password + {{- else if eq .Values.recovery.methodSettings.auth "tls" }} + sslKey: + name: {{ printf $secretName }} + key: tls.key + sslCert: + name: {{ printf $secretName }} + key: tls.crt + sslRootCert: + name: {{ printf $secretName }} + key: ca.crt + {{- end }} {{- end }} +{{- else }} + {{- fail "Invalid cluster mode!" }} {{- end }} +{{- end -}} diff --git a/charts/cluster/templates/_helpers.tpl b/charts/cluster/templates/_helpers.tpl index db3c253e5..f34825de4 100644 --- a/charts/cluster/templates/_helpers.tpl +++ b/charts/cluster/templates/_helpers.tpl @@ -63,8 +63,211 @@ If a custom imageName is available, use it, otherwise use the defaults based on {{- else if eq .Values.type "postgis" -}} {{- "ghcr.io/cloudnative-pg/postgis:14" -}} {{- else if eq .Values.type "timescaledb" -}} - {{ fail "You need to provide your own cluster.imageName as an official timescaledb image doesn't exist yet." }} + {{- fail "You need to provide your own cluster.imageName as an official timescaledb image doesn't exist yet." }} {{- else -}} - {{ fail "Invalid cluster type!" }} + {{- fail "Invalid cluster type!" }} {{- end }} {{- end -}} + +{{/* +Recovery enabled +Verify that recovery method is set to one of supported methods in methodSettings +Definition assume we have recovery enabled also in import and replication modes, if need to know +for sure that mode is set to recovery: use (eq .Values.mode "recovery") +*/}} +{{- define "cluster.recovery.enabled" -}} + {{- if and (or (eq .Values.mode "recovery") (eq .Values.mode "replica") (eq .Values.mode "import")) }} + {{- if empty .Values.recovery.method }} + {{- fail (printf ".Values.recovery.method is required, but not specified.") }} + {{- else if not (hasKey .Values.recovery.methodSettings .Values.recovery.method) }} + {{- fail (printf "The specified method '%s' does not match any of the supported in .Values.recovery.methodSettings" .Values.recovery.method) }} + {{- end }} + {{- hasKey .Values.recovery.methodSettings .Values.recovery.method }} + {{- end }} +{{- end }} + +{{/* +Recovery objectStorage enabled +Verify that provider is set to one of supported providers in providerSettings +*/}} +{{- define "cluster.recovery.method.objectStorage.enabled" -}} + {{- if and (eq (include "cluster.recovery.enabled" .) "true") (eq .Values.recovery.method "objectStorage") }} + {{- if empty .Values.recovery.methodSettings.objectStorage.provider }} + {{- fail (printf ".Values.recovery.methodSettings.objectStorage.provider is required, but not specified.") }} + {{- else if not (hasKey .Values.recovery.methodSettings.objectStorage.providerSettings .Values.recovery.methodSettings.objectStorage.provider) }} + {{- fail (printf "The specified provider '%s' does not match any of the supported in .Values.recovery.methodSettings.objectStorage.providerSettings" .Values.recovery.methodSettings.objectStorage.provider) }} + {{- end }} + {{- hasKey .Values.recovery.methodSettings.objectStorage.providerSettings .Values.recovery.methodSettings.objectStorage.provider }} + {{- end }} +{{- end }} + +{{/* +Recovery pgBasebackup enabled +*/}} +{{- define "cluster.recovery.method.pgBasebackup.enabled" -}} + {{- if (eq (include "cluster.recovery.method.pgBasebackup.auth.enabled" .) "true") }} + {{- and (eq (include "cluster.recovery.enabled" .) "true") (eq .Values.recovery.method "pgBasebackup") }} + {{- end }} +{{- end }} + +{{/* +Recovery pgBasebackup auth enabled +Verify that pgBasebackup auth is set to one of supported options in authDetails +*/}} +{{- define "cluster.recovery.method.pgBasebackup.auth.enabled" -}} + {{- if empty .Values.recovery.methodSettings.pgBasebackup.auth }} + {{- fail (printf ".Values.recovery.methodSettings.pgBasebackup.auth is required, but not specified.") }} + {{- else if not (hasKey .Values.recovery.methodSettings.pgBasebackup.authDetails .Values.recovery.methodSettings.pgBasebackup.auth) }} + {{- fail (printf "The specified auth '%s' does not match any of the supported in .Values.recovery.methodSettings.pgBasebackup.authDetails" .Values.recovery.methodSettings.pgBasebackup.auth) }} + {{- end }} + {{- hasKey .Values.recovery.methodSettings.pgBasebackup.authDetails .Values.recovery.methodSettings.pgBasebackup.auth }} +{{- end }} + +{{/* +Import enabled +Verify that import type is set to one of supported in typeSettings +*/}} +{{- define "cluster.import.enabled" -}} + {{- if eq .Values.mode "import" }} + {{- if empty .Values.import.type }} + {{- fail (printf ".Values.import.type is required, but not specified.") }} + {{- else if not (hasKey .Values.import.typeSettings .Values.import.type) }} + {{- fail (printf "The specified type '%s' does not match any of the supported in .Values.import.typeSettings" .Values.import.type) }} + {{- end }} + {{- hasKey .Values.import.typeSettings .Values.import.type }} + {{- end }} +{{- end }} + +{{/* +Import type microservice enabled +Verify that recovery method is set to pgBasebackup +*/}} +{{- define "cluster.import.type.microservice.enabled" -}} +{{- if and (eq (include "cluster.import.enabled" .) "true") (eq .Values.import.type "microservice") }} + {{- if (eq (include "cluster.recovery.method.pgBasebackup.enabled" .) "true") }} + {{- if (empty .Values.import.typeSettings.microservice.database) }} + {{- fail (printf ".Values.import.typeSettings.microservice.database is required, but not specified.") }} + {{- else }} + {{- true }} + {{- end }} + {{- else }} + {{- fail (printf "Import mode requires recovery mode to be set to 'pgBasebackup'") }} + {{- end }} +{{- else }} + {{- false }} +{{- end }} +{{- end }} + +{{/* +Import type monolith enabled +Verify that recovery method is set to pgBasebackup +*/}} +{{- define "cluster.import.type.monolith.enabled" -}} +{{- if and (eq (include "cluster.import.enabled" .) "true") (eq .Values.import.type "monolith") }} + {{- if (eq (include "cluster.recovery.method.pgBasebackup.enabled" .) "true") }} + {{- if (eq (len .Values.import.typeSettings.monolith.databases) 0) }} + {{- fail (printf ".Values.import.typeSettings.monolith.databases is required, but not specified.") }} + {{- else }} + {{- true }} + {{- end }} + {{- else }} + {{- fail (printf "Import mode requires recovery mode to be set to 'pgBasebackup'") }} + {{- end }} +{{- else }} + {{- false }} +{{- end }} +{{- end }} + +{{/* +Replica enabled +Verify that replica topology is set to one of supported in topologySettings +*/}} +{{- define "cluster.replica.enabled" -}} + {{- if eq .Values.mode "replica" }} + {{- if empty .Values.replica.topology }} + {{- fail (printf ".Values.replica.topology is required, but not specified.") }} + {{- else if not (hasKey .Values.replica.topologySettings .Values.replica.topology) }} + {{- fail (printf "The specified topology '%s' does not match any of the supported in .Values.replica.topologySettings" .Values.replica.topology) }} + {{- end }} + {{- hasKey .Values.replica.topologySettings .Values.replica.topology }} + {{- end }} +{{- end }} + +{{/* +Replica topology standalone enabled +Verify that at both recovery and backups method is set to objectStorage or pgBasebackup +*/}} +{{- define "cluster.replica.topology.standalone.enabled" -}} +{{- if and (eq (include "cluster.replica.enabled" .) "true") (eq .Values.replica.topology "standalone") }} + {{- if and (or (eq (include "cluster.recovery.method.pgBasebackup.enabled" .) "true") (eq (include "cluster.recovery.method.objectStorage.enabled" .) "true")) }} + {{- true }} + {{- else }} + {{- fail (printf "Replica in standalone topology mode requires recovery mode to be set to 'pgBasebackup' or 'objectStorage'") }} + {{- end }} +{{- else }} + {{- false }} +{{- end }} +{{- end }} + +{{/* +Replica topology distributed enabled +Validate that both recovery and backups method is set to objectStorage in distributed topology +*/}} +{{- define "cluster.replica.topology.distributed.enabled" -}} +{{- if and (eq (include "cluster.replica.enabled" .) "true") (eq .Values.replica.topology "distributed") }} + {{- if and (eq (include "cluster.recovery.method.objectStorage.enabled" .) "true") (eq (include "cluster.backups.objectStorage.enabled" .) "true") }} + {{- if (empty .Values.recovery.methodSettings.objectStorage.clusterName) }} + {{- fail (printf ".Values.recovery.methodSettings.objectStorage.clusterName is required, but not specified. Replica in distributed topology mode requires setting it up to the name of second cluster.") }} + {{- else if (eq .Values.recovery.methodSettings.objectStorage.clusterName (include "cluster.fullname" .)) }} + {{- fail (printf ".Values.recovery.methodSettings.objectStorage.clusterName is set to current cluster name, while replica in distributed topology mode requires setting it up to the name of second cluster.") }} + {{- end }} + {{- true }} + {{- else }} + {{- fail (printf "Replica in distributed topology mode requires setting up both recovery and backups to objectStorage") }} + {{- end }} +{{- else }} + {{- false }} +{{- end }} +{{- end }} + +{{/* +Replica source +Defines which source to use +*/}} +{{- define "cluster.replica.source" -}} +{{- if or (eq (include "cluster.replica.topology.standalone.enabled" .) "true") (eq (include "cluster.replica.topology.distributed.enabled" .) "true") }} + {{- if (eq (include "cluster.recovery.method.objectStorage.enabled" .) "true") }} + {{- print "objectStoreRecoveryCluster" }} + {{- else if (eq (include "cluster.recovery.method.pgBasebackup.enabled" .) "true") }} + {{- print "pgBasebackupRecoveryCluster" }} + {{- else }} + {{- fail (printf "The specified topology '%s' does not match any of the supported in .Values.replica.topologySettings" .Values.replica.topology) }} + {{- end }} +{{- end }} +{{- end }} + +{{/* +Replica readonly +Defines if we can't change anything in cluster +*/}} +{{- define "cluster.replica.readonly" -}} +{{- or (and (not .Values.replica.topologySettings.distributed.primary) (eq (include "cluster.replica.topology.distributed.enabled" .) "true")) (eq (include "cluster.replica.topology.standalone.enabled" .) "true") }} +{{- end }} + +{{/* +Backups objectStorage enabled +Validate that provider is set to one of supported providers in providerSettings +*/}} +{{- define "cluster.backups.objectStorage.enabled" -}} +{{- if and (not (empty .Values.backups.objectStorage.provider)) (not (hasKey .Values.backups.objectStorage.providerSettings .Values.backups.objectStorage.provider)) }} + {{- fail (printf "The specified provider '%s' does not match any of the supported in .Values.backups.objectStorage.providerSettings" .Values.backups.objectStorage.provider) }} +{{- end }} +{{- hasKey .Values.backups.objectStorage.providerSettings .Values.backups.objectStorage.provider }} +{{- end }} + +{{/* +Backups enabled +*/}} +{{- define "cluster.backups.enabled" -}} +{{- or (eq (include "cluster.backups.objectStorage.enabled" .) "true") (not (empty .Values.backups.volumeSnapshot.className )) -}} +{{- end }} diff --git a/charts/cluster/templates/backup-azure-creds.yaml b/charts/cluster/templates/backup-azure-creds.yaml index 6c84308dd..9a9b3087f 100644 --- a/charts/cluster/templates/backup-azure-creds.yaml +++ b/charts/cluster/templates/backup-azure-creds.yaml @@ -1,11 +1,11 @@ -{{- if and .Values.backups.enabled (eq .Values.backups.provider "azure") .Values.backups.secret.create }} +{{- if and (eq .Values.backups.objectStorage.provider "azure") (empty .Values.backups.existingSecret.name) }} apiVersion: v1 kind: Secret metadata: - name: {{ default (printf "%s-backup-azure-creds" (include "cluster.fullname" .)) .Values.backups.secret.name }} + name: {{ printf "%s-backup-azure-creds" (include "cluster.fullname" .) }} data: - AZURE_CONNECTION_STRING: {{ .Values.backups.azure.connectionString | b64enc | quote }} - AZURE_STORAGE_ACCOUNT: {{ .Values.backups.azure.storageAccount | b64enc | quote }} - AZURE_STORAGE_KEY: {{ .Values.backups.azure.storageKey | b64enc | quote }} - AZURE_STORAGE_SAS_TOKEN: {{ .Values.backups.azure.storageSasToken | b64enc | quote }} + AZURE_CONNECTION_STRING: {{ .Values.backups.objectStorage.providerSettings.azure.connectionString | b64enc | quote }} + AZURE_STORAGE_ACCOUNT: {{ .Values.backups.objectStorage.providerSettings.azure.storageAccount | b64enc | quote }} + AZURE_STORAGE_KEY: {{ .Values.backups.objectStorage.providerSettings.azure.storageKey | b64enc | quote }} + AZURE_STORAGE_SAS_TOKEN: {{ .Values.backups.objectStorage.providerSettings.azure.storageSasToken | b64enc | quote }} {{- end }} diff --git a/charts/cluster/templates/backup-google-creds.yaml b/charts/cluster/templates/backup-google-creds.yaml index cc05c4c59..3b724d3e0 100644 --- a/charts/cluster/templates/backup-google-creds.yaml +++ b/charts/cluster/templates/backup-google-creds.yaml @@ -1,8 +1,8 @@ -{{- if and .Values.backups.enabled (eq .Values.backups.provider "google") .Values.backups.secret.create }} +{{- if and (eq .Values.backups.objectStorage.provider "google") (empty .Values.backups.existingSecret.name) }} apiVersion: v1 kind: Secret metadata: - name: {{ default (printf "%s-backup-google-creds" (include "cluster.fullname" .)) .Values.backups.secret.name }} + name: {{ printf "%s-backup-google-creds" (include "cluster.fullname" .) }} data: - APPLICATION_CREDENTIALS: {{ .Values.backups.google.applicationCredentials | b64enc | quote }} + APPLICATION_CREDENTIALS: {{ .Values.backups.objectStorage.providerSettings.google.applicationCredentials | b64enc | quote }} {{- end }} diff --git a/charts/cluster/templates/backup-s3-creds.yaml b/charts/cluster/templates/backup-s3-creds.yaml index ddd8e2717..33f81bc6d 100644 --- a/charts/cluster/templates/backup-s3-creds.yaml +++ b/charts/cluster/templates/backup-s3-creds.yaml @@ -1,9 +1,9 @@ -{{- if and .Values.backups.enabled (eq .Values.backups.provider "s3") .Values.backups.secret.create }} +{{- if and (eq .Values.backups.objectStorage.provider "s3") (empty .Values.backups.existingSecret.name) }} apiVersion: v1 kind: Secret metadata: - name: {{ default (printf "%s-backup-s3-creds" (include "cluster.fullname" .)) .Values.backups.secret.name }} + name: {{ printf "%s-backup-s3-creds" (include "cluster.fullname" .) }} data: - ACCESS_KEY_ID: {{ required ".Values.backups.s3.accessKey is required, but not specified." .Values.backups.s3.accessKey | b64enc | quote }} - ACCESS_SECRET_KEY: {{ required ".Values.backups.s3.secretKey is required, but not specified." .Values.backups.s3.secretKey | b64enc | quote }} + ACCESS_KEY_ID: {{ required ".Values.backups.objectStorage.providerSettings.s3.accessKey is required, but not specified." .Values.backups.objectStorage.providerSettings.s3.accessKey | b64enc | quote }} + ACCESS_SECRET_KEY: {{ required ".Values.backups.objectStorage.providerSettings.s3.secretKey is required, but not specified." .Values.backups.objectStorage.providerSettings.s3.secretKey | b64enc | quote }} {{- end }} diff --git a/charts/cluster/templates/ca-bundle.yaml b/charts/cluster/templates/ca-bundle.yaml index 12991c163..13813df03 100644 --- a/charts/cluster/templates/ca-bundle.yaml +++ b/charts/cluster/templates/ca-bundle.yaml @@ -1,9 +1,8 @@ -{{- if .Values.backups.endpointCA.create }} +{{- if .Values.backups.objectStorage.endpointCA.create }} apiVersion: v1 kind: Secret metadata: - name: {{ .Values.backups.endpointCA.name | default (printf "%s-ca-bundle" (include "cluster.fullname" .)) | quote }} + name: {{ .Values.backups.objectStorage.endpointCA.name | default (printf "%s-ca-bundle" (include "cluster.fullname" .)) | quote }} data: - {{ .Values.backups.endpointCA.key | default "ca-bundle.crt" | quote }}: {{ .Values.backups.endpointCA.value }} - + {{ .Values.backups.objectStorage.endpointCA.key | default "ca-bundle.crt" | quote }}: {{ .Values.backups.objectStorage.endpointCA.value }} {{- end }} diff --git a/charts/cluster/templates/cluster.yaml b/charts/cluster/templates/cluster.yaml index 2dace8e34..e56a946c4 100644 --- a/charts/cluster/templates/cluster.yaml +++ b/charts/cluster/templates/cluster.yaml @@ -9,7 +9,7 @@ metadata: labels: {{- include "cluster.labels" . | nindent 4 }} {{- with .Values.cluster.additionalLabels }} - {{ toYaml . | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} spec: instances: {{ .Values.cluster.instances }} @@ -17,7 +17,7 @@ spec: imagePullPolicy: {{ .Values.cluster.imagePullPolicy }} {{- with .Values.cluster.imagePullSecrets}} imagePullSecrets: - {{- . | toYaml | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} postgresUID: {{ .Values.cluster.postgresUID }} postgresGID: {{ .Values.cluster.postgresGID }} @@ -32,25 +32,28 @@ spec: {{- with .Values.cluster.resources }} resources: {{- toYaml . | nindent 4 }} - {{ end }} + {{- end }} {{- with .Values.cluster.affinity }} affinity: {{- toYaml . | nindent 4 }} {{- end }} - priorityClassName: {{ .Values.cluster.priorityClassName }} - + {{- with .Values.cluster.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} primaryUpdateMethod: {{ .Values.cluster.primaryUpdateMethod }} primaryUpdateStrategy: {{ .Values.cluster.primaryUpdateStrategy }} logLevel: {{ .Values.cluster.logLevel }} {{- with .Values.cluster.certificates }} certificates: {{- toYaml . | nindent 4 }} - {{ end }} + {{- end }} + {{- if ne (include "cluster.replica.readonly" .) "true" }} enableSuperuserAccess: {{ .Values.cluster.enableSuperuserAccess }} {{- with .Values.cluster.superuserSecret }} superuserSecret: name: {{ . }} - {{ end }} + {{- end }} + {{- end }} postgresql: shared_preload_libraries: {{- if eq .Values.type "timescaledb" }} @@ -59,13 +62,13 @@ spec: {{- with .Values.cluster.postgresql }} parameters: {{- toYaml . | nindent 6 }} - {{ end }} + {{- end }} + {{- with .Values.cluster.roles }} managed: - {{- with .Values.cluster.roles }} roles: {{- toYaml . | nindent 6 }} - {{ end }} + {{- end }} monitoring: enablePodMonitor: {{ and .Values.cluster.monitoring.enabled .Values.cluster.monitoring.podMonitor.enabled }} @@ -74,5 +77,5 @@ spec: - name: {{ include "cluster.fullname" . }}-monitoring key: custom-queries {{- end }} - {{ include "cluster.bootstrap" . | nindent 2 }} - {{ include "cluster.backup" . | nindent 2 }} + {{- include "cluster.bootstrap" . | nindent 2 }} + {{- include "cluster.backup" . | nindent 2 }} diff --git a/charts/cluster/templates/pooler.yaml b/charts/cluster/templates/pooler.yaml index 5e01fe498..2caf2eb32 100644 --- a/charts/cluster/templates/pooler.yaml +++ b/charts/cluster/templates/pooler.yaml @@ -16,6 +16,6 @@ spec: enablePodMonitor: {{ and .Values.pooler.monitoring.enabled .Values.pooler.monitoring.podMonitor.enabled }} {{- with .Values.pooler.template }} template: - {{- . | toYaml | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} {{ end }} diff --git a/charts/cluster/templates/prometheus-rule.yaml b/charts/cluster/templates/prometheus-rule.yaml index 9b29bc692..b94f3c996 100644 --- a/charts/cluster/templates/prometheus-rule.yaml +++ b/charts/cluster/templates/prometheus-rule.yaml @@ -5,7 +5,7 @@ metadata: labels: {{- include "cluster.labels" . | nindent 4 }} {{- with .Values.cluster.additionalLabels }} - {{ toYaml . | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} name: {{ include "cluster.fullname" . }}-alert-rules spec: diff --git a/charts/cluster/templates/recovery-azure-creds.yaml b/charts/cluster/templates/recovery-azure-creds.yaml index 9fb707651..5f1d44c2b 100644 --- a/charts/cluster/templates/recovery-azure-creds.yaml +++ b/charts/cluster/templates/recovery-azure-creds.yaml @@ -1,11 +1,11 @@ -{{- if and (eq .Values.mode "recovery" ) (eq .Values.recovery.method "object_store") (eq .Values.recovery.provider "azure") .Values.recovery.secret.create }} +{{- if and (eq (include "cluster.recovery.method.objectStorage.enabled" .) "true") (eq .Values.recovery.methodSettings.objectStorage.provider "azure") (empty .Values.recovery.existingSecret.name) }} apiVersion: v1 kind: Secret metadata: - name: {{ default (printf "%s-recovery-azure-creds" (include "cluster.fullname" .)) .Values.recovery.secret.name }} + name: {{ printf "%s-recovery-azure-creds" (include "cluster.fullname" .) }} data: - AZURE_CONNECTION_STRING: {{ .Values.recovery.azure.connectionString | b64enc | quote }} - AZURE_STORAGE_ACCOUNT: {{ .Values.recovery.azure.storageAccount | b64enc | quote }} - AZURE_STORAGE_KEY: {{ .Values.recovery.azure.storageKey | b64enc | quote }} - AZURE_STORAGE_SAS_TOKEN: {{ .Values.recovery.azure.storageSasToken | b64enc | quote }} + AZURE_CONNECTION_STRING: {{ .Values.recovery.methodSettings.objectStorage.providerSettings.azure.connectionString | b64enc | quote }} + AZURE_STORAGE_ACCOUNT: {{ .Values.recovery.methodSettings.objectStorage.providerSettings.azure.storageAccount | b64enc | quote }} + AZURE_STORAGE_KEY: {{ .Values.recovery.methodSettings.objectStorage.providerSettings.azure.storageKey | b64enc | quote }} + AZURE_STORAGE_SAS_TOKEN: {{ .Values.recovery.methodSettings.objectStorage.providerSettings.azure.storageSasToken | b64enc | quote }} {{- end }} diff --git a/charts/cluster/templates/recovery-google-creds.yaml b/charts/cluster/templates/recovery-google-creds.yaml index e7366ec4c..ae50a3a51 100644 --- a/charts/cluster/templates/recovery-google-creds.yaml +++ b/charts/cluster/templates/recovery-google-creds.yaml @@ -1,8 +1,8 @@ -{{- if and (eq .Values.mode "recovery" ) (eq .Values.recovery.method "object_store") (eq .Values.recovery.provider "google") .Values.recovery.secret.create }} +{{- if and (eq (include "cluster.recovery.method.objectStorage.enabled" .) "true") (eq .Values.recovery.methodSettings.objectStorage.provider "google") (empty .Values.recovery.existingSecret.name) }} apiVersion: v1 kind: Secret metadata: - name: {{ default (printf "%s-recovery-google-creds" (include "cluster.fullname" .)) .Values.recovery.secret.name }} + name: {{ printf "%s-recovery-google-creds" (include "cluster.fullname" .) }} data: - APPLICATION_CREDENTIALS: {{ .Values.recovery.google.applicationCredentials | b64enc | quote }} + APPLICATION_CREDENTIALS: {{ .Values.recovery.methodSettings.objectStorage.providerSettings.google.applicationCredentials | b64enc | quote }} {{- end }} diff --git a/charts/cluster/templates/recovery-pg_basebackup-password.yaml b/charts/cluster/templates/recovery-pg_basebackup-password.yaml deleted file mode 100644 index 456ee75d9..000000000 --- a/charts/cluster/templates/recovery-pg_basebackup-password.yaml +++ /dev/null @@ -1,8 +0,0 @@ -{{- if and (eq .Values.mode "recovery") (eq .Values.recovery.method "pg_basebackup") .Values.recovery.pgBaseBackup.source.passwordSecret.create }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ default (printf "%s-pg-basebackup-password" (include "cluster.fullname" .)) .Values.recovery.pgBaseBackup.source.passwordSecret.name }} -data: - {{ .Values.recovery.pgBaseBackup.source.passwordSecret.key }}: {{ required ".Values.recovery.pgBaseBackup.source.passwordSecret.value required when creating a password secret." .Values.recovery.pgBaseBackup.source.passwordSecret.value | b64enc | quote }} -{{- end }} diff --git a/charts/cluster/templates/recovery-pgbb-creds.yaml b/charts/cluster/templates/recovery-pgbb-creds.yaml new file mode 100644 index 000000000..f7b6b2d9a --- /dev/null +++ b/charts/cluster/templates/recovery-pgbb-creds.yaml @@ -0,0 +1,14 @@ +{{- if and (eq (include "cluster.recovery.method.pgBasebackup.enabled" .) "true") (empty .Values.recovery.existingSecret.name) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ printf "%s-recovery-pgbb-creds" (include "cluster.fullname" .) }} +data: +{{- if eq .Values.recovery.methodSettings.pgBasebackup.auth "password" }} + password: {{ required ".Values.recovery.methodSettings.pgBasebackup.authDetails.password is required, but not specified." .Values.recovery.methodSettings.pgBasebackup.authDetails.password | b64enc | quote }} +{{- end }} +{{- else if eq .Values.recovery.methodSettings.pgBasebackup.auth "tls" }} + tls.key: {{ required ".Values.recovery.methodSettings.pgBasebackup.authDetails.tls.key is required, but not specified." .Values.recovery.methodSettings.pgBasebackup.authDetails.tls.key | b64enc | quote }} + tls.crt: {{ required ".Values.recovery.methodSettings.pgBasebackup.authDetails.tls.crt is required, but not specified." .Values.recovery.methodSettings.pgBasebackup.authDetails.tls.crt | b64enc | quote }} + ca.crt: {{ required ".Values.recovery.methodSettings.pgBasebackup.authDetails.ca.crt is required, but not specified." .Values.recovery.methodSettings.pgBasebackup.authDetails.ca.crt | b64enc | quote }} +{{- end }} diff --git a/charts/cluster/templates/recovery-s3-creds.yaml b/charts/cluster/templates/recovery-s3-creds.yaml index 950c74c4b..dba3757e9 100644 --- a/charts/cluster/templates/recovery-s3-creds.yaml +++ b/charts/cluster/templates/recovery-s3-creds.yaml @@ -1,9 +1,9 @@ -{{- if and (eq .Values.mode "recovery" ) (eq .Values.recovery.method "object_store") (eq .Values.recovery.provider "s3") .Values.recovery.secret.create }} +{{- if and (eq (include "cluster.recovery.method.objectStorage.enabled" .) "true") (eq .Values.recovery.methodSettings.objectStorage.provider "s3") (empty .Values.recovery.existingSecret.name) }} apiVersion: v1 kind: Secret metadata: - name: {{ default (printf "%s-recovery-s3-creds" (include "cluster.fullname" .)) .Values.recovery.secret.name }} + name: {{ printf "%s-recovery-s3-creds" (include "cluster.fullname" .) }} data: - ACCESS_KEY_ID: {{ required ".Values.recovery.s3.accessKey is required, but not specified." .Values.recovery.s3.accessKey | b64enc | quote }} - ACCESS_SECRET_KEY: {{ required ".Values.recovery.s3.secretKey is required, but not specified." .Values.recovery.s3.secretKey | b64enc | quote }} + ACCESS_KEY_ID: {{ required ".Values.recovery.methodSettings.objectStorage.providerSettings.s3.accessKey is required, but not specified." .Values.recovery.methodSettings.objectStorage.providerSettings.s3.accessKey | b64enc | quote }} + ACCESS_SECRET_KEY: {{ required ".Values.recovery.methodSettings.objectStorage.providerSettings.s3.secretKey is required, but not specified." .Values.recovery.methodSettings.objectStorage.providerSettings.s3.secretKey | b64enc | quote }} {{- end }} diff --git a/charts/cluster/templates/scheduled-backups.yaml b/charts/cluster/templates/scheduled-backups.yaml index 850c27940..dff2b31d5 100644 --- a/charts/cluster/templates/scheduled-backups.yaml +++ b/charts/cluster/templates/scheduled-backups.yaml @@ -1,18 +1,17 @@ -{{ if .Values.backups.enabled }} -{{ $context := . -}} -{{ range .Values.backups.scheduledBackups -}} +{{- if (eq (include "cluster.backups.enabled" .) "true") }} +{{- range .Values.backups.scheduledBackups }} --- apiVersion: postgresql.cnpg.io/v1 kind: ScheduledBackup metadata: - name: {{ include "cluster.fullname" $context }}-{{ .name }} - labels: {{ include "cluster.labels" $context | nindent 4 }} + name: {{ include "cluster.fullname" $ }}-{{ .name }} + labels: {{ include "cluster.labels" $ | nindent 4 }} spec: immediate: true schedule: {{ .schedule | quote }} method: {{ .method }} backupOwnerReference: {{ .backupOwnerReference }} cluster: - name: {{ include "cluster.fullname" $context }} -{{ end -}} -{{ end }} + name: {{ include "cluster.fullname" $ }} +{{- end }} +{{- end }} diff --git a/charts/cluster/test/monitoring/01-monitoring_cluster.yaml b/charts/cluster/test/monitoring/01-monitoring_cluster.yaml index 62559eeaa..a9edeb5b5 100644 --- a/charts/cluster/test/monitoring/01-monitoring_cluster.yaml +++ b/charts/cluster/test/monitoring/01-monitoring_cluster.yaml @@ -1,4 +1,5 @@ mode: standalone + cluster: instances: 2 storage: @@ -16,8 +17,7 @@ cluster: - ratio: usage: GAUGE description: "Cache hit ratio" -backups: - enabled: false + pooler: enabled: true instances: 1 diff --git a/charts/cluster/test/pooler/01-pooler_cluster.yaml b/charts/cluster/test/pooler/01-pooler_cluster.yaml index 307f69706..90f53eea4 100644 --- a/charts/cluster/test/pooler/01-pooler_cluster.yaml +++ b/charts/cluster/test/pooler/01-pooler_cluster.yaml @@ -1,11 +1,11 @@ mode: standalone + cluster: instances: 2 storage: size: 256Mi storageClass: standard -backups: - enabled: false + pooler: enabled: true instances: 2 diff --git a/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml b/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml index a68ef8df2..fb12c1001 100644 --- a/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml +++ b/charts/cluster/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml @@ -1,4 +1,5 @@ mode: standalone + cluster: instances: 2 imageName: ghcr.io/cloudnative-pg/crazycustomimage:99.99 @@ -67,6 +68,3 @@ cluster: foo: bar annotations: foo: bar - -backups: - enabled: false diff --git a/charts/cluster/test/postgresql-minio-backup-restore/01-standalone_cluster.yaml b/charts/cluster/test/postgresql-minio-backup-restore/01-standalone_cluster.yaml index efebd75ec..ba9911102 100644 --- a/charts/cluster/test/postgresql-minio-backup-restore/01-standalone_cluster.yaml +++ b/charts/cluster/test/postgresql-minio-backup-restore/01-standalone_cluster.yaml @@ -6,21 +6,21 @@ cluster: size: 256Mi backups: - enabled: true - provider: s3 - endpointURL: "https://minio.minio.svc.cluster.local" - endpointCA: - name: kube-root-ca.crt - key: ca.crt - wal: - encryption: "" - data: - encryption: "" - s3: - bucket: "mybucket" - path: "/v1" - accessKey: "minio" - secretKey: "minio123" - region: "local" + objectStorage: + endpointURL: https://minio.minio.svc.cluster.local + endpointCA: + name: kube-root-ca.crt + key: ca.crt + provider: s3 + providerSettings: + s3: + bucket: mybucket + path: /v1 + accessKey: minio + secretKey: minio123 + wal: + encryption: "" + data: + encryption: "" scheduledBackups: [] - retentionPolicy: "30d" + retentionPolicy: 30d diff --git a/charts/cluster/test/postgresql-minio-backup-restore/05-recovery_backup_cluster.yaml b/charts/cluster/test/postgresql-minio-backup-restore/05-recovery_backup_cluster.yaml index 7279e1e81..97c1476c8 100644 --- a/charts/cluster/test/postgresql-minio-backup-restore/05-recovery_backup_cluster.yaml +++ b/charts/cluster/test/postgresql-minio-backup-restore/05-recovery_backup_cluster.yaml @@ -7,41 +7,26 @@ cluster: recovery: method: backup - backupName: "post-init-backup" - provider: s3 - endpointURL: "https://minio.minio.svc.cluster.local" - endpointCA: - name: kube-root-ca.crt - key: ca.crt - wal: - encryption: "" - data: - encryption: "" - s3: - bucket: "mybucket" - path: "/v1" - accessKey: "minio" - secretKey: "minio123" - region: "local" - scheduledBackups: [] - retentionPolicy: "30d" + methodSettings: + backup: + name: post-init-backup backups: - enabled: true - provider: s3 - endpointURL: "https://minio.minio.svc.cluster.local" - endpointCA: - name: kube-root-ca.crt - key: ca.crt - wal: - encryption: "" - data: - encryption: "" - s3: - bucket: "mybucket" - path: "/v1" - accessKey: "minio" - secretKey: "minio123" - region: "local" + objectStorage: + endpointURL: https://minio.minio.svc.cluster.local + endpointCA: + name: kube-root-ca.crt + key: ca.crt + provider: s3 + providerSettings: + s3: + bucket: mybucket + path: /v1 + accessKey: minio + secretKey: minio123 + wal: + encryption: "" + data: + encryption: "" scheduledBackups: [] - retentionPolicy: "30d" + retentionPolicy: 30d diff --git a/charts/cluster/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster.yaml b/charts/cluster/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster.yaml index d6dafdc64..c762ad512 100644 --- a/charts/cluster/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster.yaml +++ b/charts/cluster/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster.yaml @@ -6,42 +6,37 @@ cluster: size: 256Mi recovery: - method: object_store - clusterName: "standalone-cluster" - provider: s3 - endpointURL: "https://minio.minio.svc.cluster.local" - endpointCA: - name: kube-root-ca.crt - key: ca.crt - wal: - encryption: "" - data: - encryption: "" - s3: - bucket: "mybucket" - path: "/v1" - accessKey: "minio" - secretKey: "minio123" - region: "local" - scheduledBackups: [] - retentionPolicy: "30d" + method: objectStorage + methodSettings: + objectStorage: + clusterName: standalone-cluster + endpointURL: https://minio.minio.svc.cluster.local + endpointCA: + name: kube-root-ca.crt + key: ca.crt + provider: s3 + s3: + bucket: mybucket + path: /v1 + accessKey: minio + secretKey: minio123 backups: - enabled: true - provider: s3 - endpointURL: "https://minio.minio.svc.cluster.local" - endpointCA: - name: kube-root-ca.crt - key: ca.crt - wal: - encryption: "" - data: - encryption: "" - s3: - bucket: "mybucket" - path: "/v1" - accessKey: "minio" - secretKey: "minio123" - region: "local" + objectStorage: + provider: s3 + providerSettings: + endpointURL: https://minio.minio.svc.cluster.local + endpointCA: + name: kube-root-ca.crt + key: ca.crt + s3: + bucket: mybucket + path: /v1 + accessKey: minio + secretKey: minio123 + wal: + encryption: "" + data: + encryption: "" scheduledBackups: [] - retentionPolicy: "30d" + retentionPolicy: 30d diff --git a/charts/cluster/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster.yaml b/charts/cluster/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster.yaml index 3fa2bbd03..4d567dce6 100644 --- a/charts/cluster/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster.yaml +++ b/charts/cluster/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster.yaml @@ -7,41 +7,26 @@ cluster: recovery: method: backup - backupName: "post-init-backup" - provider: s3 - endpointURL: "https://minio.minio.svc.cluster.local" - endpointCA: - name: kube-root-ca.crt - key: ca.crt - wal: - encryption: "" - data: - encryption: "" - s3: - bucket: "mybucket" - path: "/v1" - accessKey: "minio" - secretKey: "minio123" - region: "local" - scheduledBackups: [] - retentionPolicy: "30d" + methodSettings: + backup: + name: post-init-backup backups: - enabled: true - provider: s3 - endpointURL: "https://minio.minio.svc.cluster.local" - endpointCA: - name: kube-root-ca.crt - key: ca.crt - wal: - encryption: "" - data: - encryption: "" - s3: - bucket: "mybucket" - path: "/v2" - accessKey: "minio" - secretKey: "minio123" - region: "local" + objectStorage: + provider: s3 + providerSettings: + endpointURL: https://minio.minio.svc.cluster.local + endpointCA: + name: kube-root-ca.crt + key: ca.crt + s3: + bucket: mybucket + path: /v2 + accessKey: minio + secretKey: minio123 + wal: + encryption: "" + data: + encryption: "" scheduledBackups: [] - retentionPolicy: "30d" + retentionPolicy: 30d diff --git a/charts/cluster/test/postgresql-pg_basebackup/00-source-cluster.yaml b/charts/cluster/test/postgresql-pg_basebackup/00-source-cluster.yaml index 3d041f0f3..7f4d98023 100644 --- a/charts/cluster/test/postgresql-pg_basebackup/00-source-cluster.yaml +++ b/charts/cluster/test/postgresql-pg_basebackup/00-source-cluster.yaml @@ -1,5 +1,4 @@ -mode: "standalone" +mode: standalone + cluster: instances: 1 -backups: - enabled: false \ No newline at end of file diff --git a/charts/cluster/test/postgresql-pg_basebackup/02-pg_basebackup-cluster.yaml b/charts/cluster/test/postgresql-pg_basebackup/02-pg_basebackup-cluster.yaml index 615ad3c80..9c4697783 100644 --- a/charts/cluster/test/postgresql-pg_basebackup/02-pg_basebackup-cluster.yaml +++ b/charts/cluster/test/postgresql-pg_basebackup/02-pg_basebackup-cluster.yaml @@ -1,21 +1,17 @@ -mode: "recovery" -recovery: - method: "pg_basebackup" - pgBaseBackup: - source: - host: "source-cluster-rw" - database: "mygooddb" - username: "streaming_replica" - sslMode: "require" - sslKeySecret: - name: source-cluster-replication - key: tls.key - sslCertSecret: - name: source-cluster-replication - key: tls.crt +mode: recovery cluster: instances: 2 -backups: - enabled: false \ No newline at end of file +recovery: + existingSecret: + name: source-cluster-replication + method: pgBasebackup + methodSettings: + pgBasebackup: + connectionParameters: + host: source-cluster-rw + database: mygooddb + username: streaming_replica + sslMode: require + auth: tls diff --git a/charts/cluster/values.schema.json b/charts/cluster/values.schema.json index 1ef5bba79..9378435c9 100644 --- a/charts/cluster/values.schema.json +++ b/charts/cluster/values.schema.json @@ -5,118 +5,147 @@ "backups": { "type": "object", "properties": { - "azure": { + "existingSecret": { "type": "object", "properties": { - "connectionString": { - "type": "string" - }, - "containerName": { - "type": "string" - }, - "inheritFromAzureAD": { - "type": "boolean" - }, - "path": { - "type": "string" - }, - "serviceName": { - "type": "string" - }, - "storageAccount": { - "type": "string" - }, - "storageKey": { - "type": "string" - }, - "storageSasToken": { - "type": "string" - } - } - }, - "data": { - "type": "object", - "properties": { - "compression": { - "type": "string" - }, - "encryption": { + "name": { "type": "string" - }, - "jobs": { - "type": "integer" } } }, - "destinationPath": { - "type": "string" - }, - "enabled": { - "type": "boolean" - }, - "endpointCA": { + "objectStorage": { "type": "object", "properties": { - "create": { - "type": "boolean" + "data": { + "type": "object", + "properties": { + "compression": { + "type": "string" + }, + "encryption": { + "type": "string" + }, + "jobs": { + "type": "integer" + } + } }, - "key": { + "destinationPath": { "type": "string" }, - "name": { - "type": "string" + "endpointCA": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } }, - "value": { - "type": "string" - } - } - }, - "endpointURL": { - "type": "string" - }, - "google": { - "type": "object", - "properties": { - "applicationCredentials": { + "endpointURL": { "type": "string" }, - "bucket": { + "provider": { "type": "string" }, - "gkeEnvironment": { - "type": "boolean" + "providerSettings": { + "type": "object", + "properties": { + "azure": { + "type": "object", + "properties": { + "connectionString": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "inheritFromAzureAD": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "serviceName": { + "type": "string" + }, + "storageAccount": { + "type": "string" + }, + "storageKey": { + "type": "string" + }, + "storageSasToken": { + "type": "string" + } + } + }, + "google": { + "type": "object", + "properties": { + "applicationCredentials": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "gkeEnvironment": { + "type": "boolean" + }, + "path": { + "type": "string" + } + } + }, + "s3": { + "type": "object", + "properties": { + "accessKey": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "path": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secretKey": { + "type": "string" + } + } + } + } }, - "path": { - "type": "string" + "wal": { + "type": "object", + "properties": { + "compression": { + "type": "string" + }, + "encryption": { + "type": "string" + }, + "maxParallel": { + "type": "integer" + } + } } } }, - "provider": { - "type": "string" - }, "retentionPolicy": { "type": "string" }, - "s3": { - "type": "object", - "properties": { - "accessKey": { - "type": "string" - }, - "bucket": { - "type": "string" - }, - "path": { - "type": "string" - }, - "region": { - "type": "string" - }, - "secretKey": { - "type": "string" - } - } - }, "scheduledBackups": { "type": "array", "items": { @@ -137,28 +166,34 @@ } } }, - "secret": { - "type": "object", - "properties": { - "create": { - "type": "boolean" - }, - "name": { - "type": "string" - } - } + "target": { + "type": "string" }, - "wal": { + "volumeSnapshot": { "type": "object", "properties": { - "compression": { + "className": { "type": "string" }, - "encryption": { + "online": { + "type": "boolean" + }, + "onlineConfiguration": { + "type": "object", + "properties": { + "immediateCheckpoint": { + "type": "boolean" + }, + "waitForArchive": { + "type": "boolean" + } + } + }, + "snapshotOwnerReference": { "type": "string" }, - "maxParallel": { - "type": "integer" + "walClassName": { + "type": "string" } } } @@ -289,6 +324,44 @@ "fullnameOverride": { "type": "string" }, + "import": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "typeSettings": { + "type": "object", + "properties": { + "microservice": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "postImportApplicationSQL": { + "type": "array" + } + } + }, + "monolith": { + "type": "object", + "properties": { + "databases": { + "type": "array" + }, + "roles": { + "type": "array" + } + } + } + } + } + } + }, "mode": { "type": "string" }, @@ -345,106 +418,38 @@ "recovery": { "type": "object", "properties": { - "azure": { - "type": "object", - "properties": { - "connectionString": { - "type": "string" - }, - "containerName": { - "type": "string" - }, - "inheritFromAzureAD": { - "type": "boolean" - }, - "path": { - "type": "string" - }, - "serviceName": { - "type": "string" - }, - "storageAccount": { - "type": "string" - }, - "storageKey": { - "type": "string" - }, - "storageSasToken": { - "type": "string" - } - } - }, - "backupName": { - "type": "string" - }, - "clusterName": { - "type": "string" - }, - "destinationPath": { - "type": "string" - }, - "endpointCA": { + "existingSecret": { "type": "object", "properties": { - "create": { - "type": "boolean" - }, - "key": { - "type": "string" - }, "name": { "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "endpointURL": { - "type": "string" - }, - "google": { - "type": "object", - "properties": { - "applicationCredentials": { - "type": "string" - }, - "bucket": { - "type": "string" - }, - "gkeEnvironment": { - "type": "boolean" - }, - "path": { - "type": "string" } } }, "method": { "type": "string" }, - "pgBaseBackup": { + "methodSettings": { "type": "object", "properties": { - "database": { - "type": "string" - }, - "owner": { - "type": "string" - }, - "secret": { - "type": "string" + "backup": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } }, - "source": { + "objectStorage": { "type": "object", "properties": { - "database": { + "clusterName": { "type": "string" }, - "host": { + "destinationPath": { "type": "string" }, - "passwordSecret": { + "endpointCA": { "type": "object", "properties": { "create": { @@ -461,46 +466,151 @@ } } }, - "port": { - "type": "integer" + "endpointURL": { + "type": "string" + }, + "provider": { + "type": "string" }, - "sslCertSecret": { + "providerSettings": { "type": "object", "properties": { - "key": { - "type": "string" + "azure": { + "type": "object", + "properties": { + "connectionString": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "inheritFromAzureAD": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "serviceName": { + "type": "string" + }, + "storageAccount": { + "type": "string" + }, + "storageKey": { + "type": "string" + }, + "storageSasToken": { + "type": "string" + } + } }, - "name": { - "type": "string" + "google": { + "type": "object", + "properties": { + "applicationCredentials": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "gkeEnvironment": { + "type": "boolean" + }, + "path": { + "type": "string" + } + } + }, + "s3": { + "type": "object", + "properties": { + "accessKey": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "path": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secretKey": { + "type": "string" + } + } } } + } + } + }, + "pgBasebackup": { + "type": "object", + "properties": { + "auth": { + "type": "string" }, - "sslKeySecret": { + "authDetails": { "type": "object", "properties": { - "key": { + "password": { "type": "string" }, - "name": { - "type": "string" + "tls": { + "type": "object", + "properties": { + "ca": { + "type": "string" + }, + "crt": { + "type": "string" + }, + "key": { + "type": "string" + } + } } } }, - "sslMode": { - "type": "string" - }, - "sslRootCertSecret": { + "connectionParameters": { "type": "object", "properties": { - "key": { + "database": { "type": "string" }, - "name": { + "host": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "sslMode": { + "type": "string" + }, + "user": { "type": "string" } } }, - "username": { + "database": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "ownerSecret": { + "type": "string" + } + } + }, + "volumeSnapshot": { + "type": "object", + "properties": { + "storageSnapshotName": { + "type": "string" + }, + "walSnapshotName": { "type": "string" } } @@ -514,38 +624,36 @@ "type": "string" } } - }, - "provider": { + } + } + }, + "replica": { + "type": "object", + "properties": { + "topology": { "type": "string" }, - "s3": { + "topologySettings": { "type": "object", "properties": { - "accessKey": { - "type": "string" - }, - "bucket": { - "type": "string" - }, - "path": { - "type": "string" - }, - "region": { - "type": "string" - }, - "secretKey": { - "type": "string" - } - } - }, - "secret": { - "type": "object", - "properties": { - "create": { - "type": "boolean" + "distributed": { + "type": "object", + "properties": { + "primary": { + "type": "boolean" + }, + "promotionToken": { + "type": "string" + } + } }, - "name": { - "type": "string" + "standalone": { + "type": "object", + "properties": { + "minApplyDelay": { + "type": "string" + } + } } } } diff --git a/charts/cluster/values.yaml b/charts/cluster/values.yaml index 0ee58d7da..4b5d2751e 100644 --- a/charts/cluster/values.yaml +++ b/charts/cluster/values.yaml @@ -12,108 +12,11 @@ type: postgresql ### # -- Cluster mode of operation. Available modes: # * `standalone` - default mode. Creates new or updates an existing CNPG cluster. -# * `replica` - Creates a replica cluster from an existing CNPG cluster. # TODO -# * `recovery` - Same as standalone but creates a cluster from a backup, object store or via pg_basebackup. +# * `import` - Creates a cluster by utilizing `pg_dump -Fc` from existing PostgreSQL, allows to migrate even from very old versions of PostgreSQL. +# * `recovery` - Creates a cluster from a backup, object store, pg_basebackup or volumeSnapshot. +# * `replica` - Creates a replica cluster from object store or pg_basebackup with settings defined in recovery method. mode: standalone -recovery: - ## - # -- Available recovery methods: - # * `backup` - Recovers a CNPG cluster from a CNPG backup (PITR supported) Needs to be on the same cluster in the same namespace. - # * `object_store` - Recovers a CNPG cluster from a barman object store (PITR supported). - # * `pg_basebackup` - Recovers a CNPG cluster viaa streaming replication protocol. Useful if you want to - # migrate databases to CloudNativePG, even from outside Kubernetes. # TODO - method: backup - - ## -- Point in time recovery target. Specify one of the following: - pitrTarget: - # -- Time in RFC3339 format - time: "" - - ## - # -- Backup Recovery Method - backupName: "" # Name of the backup to recover from. Required if method is `backup`. - - ## - # -- The original cluster name when used in backups. Also known as serverName. - clusterName: "" - # -- Overrides the provider specific default endpoint. Defaults to: - # S3: https://s3..amazonaws.com" - # Leave empty if using the default S3 endpoint - endpointURL: "" - # -- Specifies a CA bundle to validate a privately signed certificate. - endpointCA: - # -- Creates a secret with the given value if true, otherwise uses an existing secret. - create: false - name: "" - key: "" - value: "" - # -- Overrides the provider specific default path. Defaults to: - # S3: s3:// - # Azure: https://..core.windows.net/ - # Google: gs:// - destinationPath: "" - # -- One of `s3`, `azure` or `google` - provider: s3 - s3: - region: "" - bucket: "" - path: "/" - accessKey: "" - secretKey: "" - azure: - path: "/" - connectionString: "" - storageAccount: "" - storageKey: "" - storageSasToken: "" - containerName: "" - serviceName: blob - inheritFromAzureAD: false - google: - path: "/" - bucket: "" - gkeEnvironment: false - applicationCredentials: "" - secret: - # -- Whether to create a secret for the backup credentials - create: true - # -- Name of the backup credentials secret - name: "" - - # See https://cloudnative-pg.io/documentation/1.22/bootstrap/#bootstrap-from-a-live-cluster-pg_basebackup - pgBaseBackup: - # -- Name of the database used by the application. Default: `app`. - database: app - # -- Name of the owner of the database in the instance to be used by applications. Defaults to the value of the `database` key. - secret: "" - # -- Name of the secret containing the initial credentials for the owner of the user database. If empty a new secret will be created from scratch - owner: "" - source: - host: "" - port: 5432 - username: "" - database: "app" - sslMode: "verify-full" - passwordSecret: - # -- Whether to create a secret for the password - create: false - # -- Name of the secret containing the password - name: "" - # -- The key in the secret containing the password - key: "password" - # -- The password value to use when creating the secret - value: "" - sslKeySecret: - name: "" - key: "" - sslCertSecret: - name: "" - key: "" - sslRootCertSecret: - name: "" - key: "" - cluster: # -- Number of instances @@ -247,68 +150,265 @@ cluster: annotations: {} -backups: - # -- You need to configure backups manually, so backups are disabled by default. - enabled: false +import: + # -- Choose one of types from `typeSettings`, + # https://cloudnative-pg.io/documentation/current/database_import/ + # All types require: configure `recovery.method` to `pgBasebackup` and `recovery.methodSettings` accordingly + # Please be aware off https://cloudnative-pg.io/documentation/current/database_import/#import-optimizations + type: "" + typeSettings: + microservice: + # -- Database name to import + database: "" + # -- Configure database owner, defaults to the database name + owner: "" + # -- Execute defined SQL queries in the application database after import, optional + postImportApplicationSQL: [] + # - CREATE EXTENSION IF NOT EXISTS vector; + monolith: + # -- List of databases that is required by the imported. Wildcard allow to import all databases. + databases: [] + # -- List of role that is required by the imported databases. Wildcard allow to import all roles. + # Notes: + # 1. postgres, streaming_replica & cnp_pooler_pgbouncer roles will not be imported from origin + # 2. the SUPERUSER option is removed from any imported role + roles: [] + + +replica: + # -- Choose one of topologies from `topologySettings`, + # https://cloudnative-pg.io/documentation/current/replica_cluster/ + # standalone: configure `recovery.method` to one of `objectStorage` or `pgBasebackup` and `recovery.methodSettings` accordingly + # distributed: configure `recovery.method` to `objectStorage` and `recovery.methodSettings` + topology: "" + topologySettings: + standalone: + # -- Deleyed replication, disabled if empty, set enable set time, f.e: 1h + # https://cloudnative-pg.io/documentation/current/replica_cluster/#delayed-replicas + minApplyDelay: "" + distributed: + # -- Distributed topology requires to use objectStorage in both recovery and backups + primary: true + # -- Promoting a Replica to a Primary Cluster + # demotionToken obtrained from demoted primary should set to promotionToken on replica + # Use `kubectl get cluster cluster-eu-south -o jsonpath='{.status.demotionToken}'` + # https://cloudnative-pg.io/documentation/current/replica_cluster/#demoting-a-primary-to-a-replica-cluster + # https://cloudnative-pg.io/documentation/current/replica_cluster/#promoting-a-replica-to-a-primary-cluster + promotionToken: "" - # -- Overrides the provider specific default endpoint. Defaults to: - # S3: https://s3..amazonaws.com" - endpointURL: "" # Leave empty if using the default S3 endpoint - # -- Specifies a CA bundle to validate a privately signed certificate. - endpointCA: - # -- Creates a secret with the given value if true, otherwise uses an existing secret. - create: false + +recovery: + # -- One of methods from `methodSettings`. + method: "" + + pitrTarget: + # -- Point in time recovery target. + # Work with backup, objectStorage and volumeSnapshot methods. + # Time should be set in RFC3339 format. + time: "" + + existingSecret: + # -- If the secret name is set, helm chart will create one which needed. + # Existing secret should contains all required veriables for chosen method or provider. name: "" - key: "" - value: "" - - # -- Overrides the provider specific default path. Defaults to: - # S3: s3:// - # Azure: https://..core.windows.net/ - # Google: gs:// - destinationPath: "" - # -- One of `s3`, `azure` or `google` - provider: s3 - s3: - region: "" - bucket: "" - path: "/" - accessKey: "" - secretKey: "" - azure: - path: "/" - connectionString: "" - storageAccount: "" - storageKey: "" - storageSasToken: "" - containerName: "" - serviceName: blob - inheritFromAzureAD: false - google: - path: "/" - bucket: "" - gkeEnvironment: false - applicationCredentials: "" - secret: - # -- Whether to create a secret for the backup credentials - create: true - # -- Name of the backup credentials secret + + methodSettings: + backup: + # -- Recovers a CNPG cluster from a backups.postgresql.cnpg.io custom resource (PITR supported). + # https://cloudnative-pg.io/documentation/current/recovery/#recovery-from-a-backup-object + # Needs to be on the same cluster in the same namespace. + # Name of the backup to recover from. + name: "" + objectStorage: + # -- Recovers a CNPG cluster from a barman object store (PITR supported). + # https://cloudnative-pg.io/documentation/current/recovery/#recovery-from-an-object-store + # https://cloudnative-pg.io/documentation/current/replica_cluster/#example-of-standalone-replica-cluster-from-an-object-store + # The original cluster name when used in backups. Also known as serverName. + clusterName: "" + # -- Enables objectStorage provider. One of providers from `providerSettings`. + # https://cloudnative-pg.io/documentation/current/appendixes/object_stores/#appendix-a-common-object-stores-for-backups + provider: "" + providerSettings: + s3: + region: "" + bucket: "" + path: "/" + # -- Configures `ACCESS_KEY_ID` in secret + accessKey: "" + # -- Configures `ACCESS_SECRET_KEY` in secret + secretKey: "" + azure: + path: "/" + # -- Configures `AZURE_CONNECTION_STRING` in secret + connectionString: "" + # -- Configures `AZURE_STORAGE_ACCOUNT` in secret + storageAccount: "" + # -- Configures `AZURE_STORAGE_KEY` in secret + storageKey: "" + # -- Configures `AZURE_STORAGE_SAS_TOKEN` in secret + storageSasToken: "" + containerName: "" + serviceName: blob + inheritFromAzureAD: false + google: + path: "/" + bucket: "" + gkeEnvironment: false + # -- Configures `APPLICATION_CREDENTIALS` in secret + applicationCredentials: "" + # -- Overrides the provider specific default endpoint. Defaults to: + # S3: https://s3..amazonaws.com" + # Leave empty if using the default S3 endpoint + endpointURL: "" + # -- Specifies a CA bundle to validate a privately signed certificate. + endpointCA: + # -- Creates a secret with the given value if true, otherwise uses an existing secret. + create: false + name: "" + key: "" + value: "" + # -- Overrides the provider specific default path. Defaults to: + # S3: s3:// + # Azure: https://..core.windows.net/ + # Google: gs:// + destinationPath: "" + volumeSnapshot: + # -- Recovers a CNPG cluster from a volume snapshot (PITR supported). + # https://cloudnative-pg.io/documentation/current/recovery/#recovery-from-volumesnapshot-objects + storageSnapshotName: "" + # -- WAL snapshot name, optional, need to be set if WAL stored on separate PVC. + walSnapshotName: "" + pgBasebackup: + # -- Recovers a CNPG cluster via streaming replication protocol. + # https://cloudnative-pg.io/documentation/current/bootstrap/#bootstrap-from-a-live-cluster-pg_basebackup + # https://cloudnative-pg.io/documentation/current/replica_cluster/#example-of-standalone-replica-cluster-using-pg_basebackup + connectionParameters: + host: "" + port: 5432 + user: "" + # -- SSL mode to use while connecting to host. + # Possible secure options: `verify-full`, `verify-ca`, `require` and insecure: `prefer`, `allow`, `disable`. + # For more details please see: https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-PROTECTION + sslMode: verify-full + # -- Database on source server, optional. + # If `pgBasebackup.database` set and this setting is empty - will use same database name. + database: "" + # -- Configure one of supported auth types: `password` or `tls` + auth: password + authDetails: + # -- Configures `password` in secret + password: "" + tls: + # -- Configures `tls.key` in secret + key: "" + # -- Configures `tls.crt` in secret + crt: "" + # -- Configures `ca.crt` in secret + ca: "" + # -- Configure application database, optional and ignored with replica + # https://cloudnative-pg.io/documentation/current/bootstrap/#configure-the-application-database + database: "" + # -- Configure database owner, defaults to the database name + owner: "" + # -- Name of the secret containing the initial credentials for the owner of the user database. + # Secret must contains `username` key that match `owner` and `password` key. + # If empty - password will be generated randomly and saved to secret generated by Operator. + ownerSecret: "" + + +backups: + existingSecret: + # -- If the secret name is set, helm chart will create one which needed. + # Existing secret should contains all required veriables for chosen provider. name: "" - wal: - # -- WAL compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. - compression: gzip - # -- Whether to instruct the storage provider to encrypt WAL files. One of `` (use the storage container default), `AES256` or `aws:kms`. - encryption: AES256 - # -- Number of WAL files to be archived or restored in parallel. - maxParallel: 1 - data: - # -- Data compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. - compression: gzip - # -- Whether to instruct the storage provider to encrypt data files. One of `` (use the storage container default), `AES256` or `aws:kms`. - encryption: AES256 - # -- Number of data files to be archived or restored in parallel. - jobs: 2 + objectStorage: + # -- Enables objectStorage provider. One of providers from `providerSettings`, empty string - disables objectStorage backups. + # https://cloudnative-pg.io/documentation/current/appendixes/object_stores/#appendix-a-common-object-stores-for-backups + provider: "" + providerSettings: + s3: + region: "" + bucket: "" + path: "/" + # -- Configures `ACCESS_KEY_ID` in secret + accessKey: "" + # -- Configures `ACCESS_SECRET_KEY` in secret + secretKey: "" + azure: + path: "/" + # -- Configures `AZURE_CONNECTION_STRING` in secret + connectionString: "" + # -- Configures `AZURE_STORAGE_ACCOUNT` in secret + storageAccount: "" + # -- Configures `AZURE_STORAGE_KEY` in secret + storageKey: "" + # -- Configures `AZURE_STORAGE_SAS_TOKEN` in secret + storageSasToken: "" + containerName: "" + serviceName: blob + inheritFromAzureAD: false + google: + path: "/" + bucket: "" + gkeEnvironment: false + # -- Configures `APPLICATION_CREDENTIALS` in secret + applicationCredentials: "" + # -- Overrides the provider specific default endpoint. Defaults to: + # S3: https://s3..amazonaws.com" + endpointURL: "" # Leave empty if using the default S3 endpoint + endpointCA: + # -- Specifies a CA bundle to validate a privately signed certificate. + # Creates a secret with the given value if true, otherwise uses an existing secret. + create: false + name: "" + key: "" + value: "" + # -- Overrides the provider specific default path. Defaults to: + # S3: s3:// + # Azure: https://..core.windows.net/ + # Google: gs:// + destinationPath: "" + + wal: + # -- WAL compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. + compression: gzip + # -- Whether to instruct the storage provider to encrypt WAL files. One of `` (use the storage container default), `AES256` or `aws:kms`. + encryption: AES256 + # -- Number of WAL files to be archived or restored in parallel. + maxParallel: 1 + data: + # -- Data compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. + compression: gzip + # -- Whether to instruct the storage provider to encrypt data files. One of `` (use the storage container default), `AES256` or `aws:kms`. + encryption: AES256 + # -- Number of data files to be archived or restored in parallel. + jobs: 2 + + volumeSnapshot: + # -- To enable volumeSnapshot configure className and add scheduledBackup with method `volumeSnapshot` + # https://cloudnative-pg.io/documentation/current/backup_volumesnapshot/#how-to-configure-volume-snapshot-backups + className: "" + # -- WAL snapshots class name, if empty - defaults to `className` + walClassName: "" + # -- Hot and cold backups + # https://cloudnative-pg.io/documentation/current/backup_volumesnapshot/#hot-and-cold-backups + online: true + onlineConfiguration: + immediateCheckpoint: true + waitForArchive: true + # -- Persistence of volume snapshot objects + # https://cloudnative-pg.io/documentation/current/backup_volumesnapshot/#persistence-of-volume-snapshot-objects + # One of `none`, `backup`, `cluster`, + # note: `retentionPolicy` will work only with `backup` + snapshotOwnerReference: backup + + # -- Backup target configuration. One of `prefer-standby`, `primary`. + # https://cloudnative-pg.io/documentation/current/backup/#backup-from-a-standby + target: prefer-standby + + # -- Retention policy for backups + retentionPolicy: 30d scheduledBackups: - @@ -321,9 +421,6 @@ backups: # -- Backup method, can be `barmanObjectStore` (default) or `volumeSnapshot` method: barmanObjectStore - # -- Retention policy for backups - retentionPolicy: "30d" - pooler: # -- Whether to enable PgBouncer