mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-09-30 05:52:43 +02:00
configurable resources for logical backup pod template (#710)
* new config options to specify resources for logical backup jobs * bug in logical backup script for s3 dumps * define enum for logical_backup_provider * changed order of logical backup azure options * fix unit test for stream comparison
This commit is contained in:
@@ -1618,6 +1618,23 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
|
||||
"logical_backup": {
|
||||
Type: "object",
|
||||
Properties: map[string]apiextv1.JSONSchemaProps{
|
||||
"logical_backup_azure_storage_account_name": {
|
||||
Type: "string",
|
||||
},
|
||||
"logical_backup_azure_storage_container": {
|
||||
Type: "string",
|
||||
},
|
||||
"logical_backup_azure_storage_account_key": {
|
||||
Type: "string",
|
||||
},
|
||||
"logical_backup_cpu_limit": {
|
||||
Type: "string",
|
||||
Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$",
|
||||
},
|
||||
"logical_backup_cpu_request": {
|
||||
Type: "string",
|
||||
Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$",
|
||||
},
|
||||
"logical_backup_docker_image": {
|
||||
Type: "string",
|
||||
},
|
||||
@@ -1627,8 +1644,27 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
|
||||
"logical_backup_job_prefix": {
|
||||
Type: "string",
|
||||
},
|
||||
"logical_backup_memory_limit": {
|
||||
Type: "string",
|
||||
Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$",
|
||||
},
|
||||
"logical_backup_memory_request": {
|
||||
Type: "string",
|
||||
Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$",
|
||||
},
|
||||
"logical_backup_provider": {
|
||||
Type: "string",
|
||||
Enum: []apiextv1.JSON{
|
||||
{
|
||||
Raw: []byte(`"az"`),
|
||||
},
|
||||
{
|
||||
Raw: []byte(`"gcs"`),
|
||||
},
|
||||
{
|
||||
Raw: []byte(`"s3"`),
|
||||
},
|
||||
},
|
||||
},
|
||||
"logical_backup_s3_access_key_id": {
|
||||
Type: "string",
|
||||
@@ -1655,15 +1691,6 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
|
||||
Type: "string",
|
||||
Pattern: "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$",
|
||||
},
|
||||
"logical_backup_azure_storage_account_name": {
|
||||
Type: "string",
|
||||
},
|
||||
"logical_backup_azure_storage_container": {
|
||||
Type: "string",
|
||||
},
|
||||
"logical_backup_azure_storage_account_key": {
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
"debug": {
|
||||
|
||||
@@ -218,6 +218,9 @@ type OperatorLogicalBackupConfiguration struct {
|
||||
Schedule string `json:"logical_backup_schedule,omitempty"`
|
||||
DockerImage string `json:"logical_backup_docker_image,omitempty"`
|
||||
BackupProvider string `json:"logical_backup_provider,omitempty"`
|
||||
AzureStorageAccountName string `json:"logical_backup_azure_storage_account_name,omitempty"`
|
||||
AzureStorageContainer string `json:"logical_backup_azure_storage_container,omitempty"`
|
||||
AzureStorageAccountKey string `json:"logical_backup_azure_storage_account_key,omitempty"`
|
||||
S3Bucket string `json:"logical_backup_s3_bucket,omitempty"`
|
||||
S3Region string `json:"logical_backup_s3_region,omitempty"`
|
||||
S3Endpoint string `json:"logical_backup_s3_endpoint,omitempty"`
|
||||
@@ -227,9 +230,10 @@ type OperatorLogicalBackupConfiguration struct {
|
||||
RetentionTime string `json:"logical_backup_s3_retention_time,omitempty"`
|
||||
GoogleApplicationCredentials string `json:"logical_backup_google_application_credentials,omitempty"`
|
||||
JobPrefix string `json:"logical_backup_job_prefix,omitempty"`
|
||||
AzureStorageAccountName string `json:"logical_backup_azure_storage_account_name,omitempty"`
|
||||
AzureStorageContainer string `json:"logical_backup_azure_storage_container,omitempty"`
|
||||
AzureStorageAccountKey string `json:"logical_backup_azure_storage_account_key,omitempty"`
|
||||
CPURequest string `json:"logical_backup_cpu_request,omitempty"`
|
||||
MemoryRequest string `json:"logical_backup_memory_request,omitempty"`
|
||||
CPULimit string `json:"logical_backup_cpu_limit,omitempty"`
|
||||
MemoryLimit string `json:"logical_backup_memory_limit,omitempty"`
|
||||
}
|
||||
|
||||
// PatroniConfiguration defines configuration for Patroni
|
||||
|
||||
+22
-2
@@ -139,6 +139,23 @@ func makeDefaultResources(config *config.Config) acidv1.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
func makeLogicalBackupResources(config *config.Config) acidv1.Resources {
|
||||
|
||||
logicalBackupResourceRequests := acidv1.ResourceDescription{
|
||||
CPU: config.LogicalBackup.LogicalBackupCPURequest,
|
||||
Memory: config.LogicalBackup.LogicalBackupMemoryRequest,
|
||||
}
|
||||
logicalBackupResourceLimits := acidv1.ResourceDescription{
|
||||
CPU: config.LogicalBackup.LogicalBackupCPULimit,
|
||||
Memory: config.LogicalBackup.LogicalBackupMemoryLimit,
|
||||
}
|
||||
|
||||
return acidv1.Resources{
|
||||
ResourceRequests: logicalBackupResourceRequests,
|
||||
ResourceLimits: logicalBackupResourceLimits,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cluster) enforceMinResourceLimits(resources *v1.ResourceRequirements) error {
|
||||
var (
|
||||
isSmaller bool
|
||||
@@ -2107,9 +2124,12 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1.CronJob, error) {
|
||||
|
||||
c.logger.Debug("Generating logical backup pod template")
|
||||
|
||||
// allocate for the backup pod the same amount of resources as for normal DB pods
|
||||
// allocate configured resources for logical backup pod
|
||||
logicalBackupResources := makeLogicalBackupResources(&c.OpConfig)
|
||||
// if not defined only default resources from spilo pods are used
|
||||
resourceRequirements, err = c.generateResourceRequirements(
|
||||
c.Spec.Resources, makeDefaultResources(&c.OpConfig), logicalBackupContainerName)
|
||||
&logicalBackupResources, makeDefaultResources(&c.OpConfig), logicalBackupContainerName)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not generate resource requirements for logical backup pods: %v", err)
|
||||
}
|
||||
|
||||
+132
-2
@@ -2638,7 +2638,6 @@ func TestGenerateResourceRequirements(t *testing.T) {
|
||||
clusterName := "acid-test-cluster"
|
||||
namespace := "default"
|
||||
clusterNameLabel := "cluster-name"
|
||||
roleLabel := "spilo-role"
|
||||
sidecarName := "postgres-exporter"
|
||||
|
||||
// enforceMinResourceLimits will be called 2 twice emitting 4 events (2x cpu, 2x memory raise)
|
||||
@@ -2657,7 +2656,7 @@ func TestGenerateResourceRequirements(t *testing.T) {
|
||||
DefaultMemoryLimit: "500Mi",
|
||||
MaxMemoryRequest: "1Gi",
|
||||
MinMemoryLimit: "250Mi",
|
||||
PodRoleLabel: roleLabel,
|
||||
PodRoleLabel: "spilo-role",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@@ -3008,6 +3007,137 @@ func TestGenerateResourceRequirements(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateLogicalBackupJob(t *testing.T) {
|
||||
clusterName := "acid-test-cluster"
|
||||
configResources := config.Resources{
|
||||
DefaultCPURequest: "100m",
|
||||
DefaultCPULimit: "1",
|
||||
DefaultMemoryRequest: "100Mi",
|
||||
DefaultMemoryLimit: "500Mi",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
subTest string
|
||||
config config.Config
|
||||
specSchedule string
|
||||
expectedSchedule string
|
||||
expectedJobName string
|
||||
expectedResources acidv1.Resources
|
||||
}{
|
||||
{
|
||||
subTest: "test generation of logical backup pod resources when not configured",
|
||||
config: config.Config{
|
||||
LogicalBackup: config.LogicalBackup{
|
||||
LogicalBackupJobPrefix: "logical-backup-",
|
||||
LogicalBackupSchedule: "30 00 * * *",
|
||||
},
|
||||
Resources: configResources,
|
||||
PodManagementPolicy: "ordered_ready",
|
||||
SetMemoryRequestToLimit: false,
|
||||
},
|
||||
specSchedule: "",
|
||||
expectedSchedule: "30 00 * * *",
|
||||
expectedJobName: "logical-backup-acid-test-cluster",
|
||||
expectedResources: acidv1.Resources{
|
||||
ResourceRequests: acidv1.ResourceDescription{CPU: "100m", Memory: "100Mi"},
|
||||
ResourceLimits: acidv1.ResourceDescription{CPU: "1", Memory: "500Mi"},
|
||||
},
|
||||
},
|
||||
{
|
||||
subTest: "test generation of logical backup pod resources when configured",
|
||||
config: config.Config{
|
||||
LogicalBackup: config.LogicalBackup{
|
||||
LogicalBackupCPURequest: "10m",
|
||||
LogicalBackupCPULimit: "300m",
|
||||
LogicalBackupMemoryRequest: "50Mi",
|
||||
LogicalBackupMemoryLimit: "300Mi",
|
||||
LogicalBackupJobPrefix: "lb-",
|
||||
LogicalBackupSchedule: "30 00 * * *",
|
||||
},
|
||||
Resources: configResources,
|
||||
PodManagementPolicy: "ordered_ready",
|
||||
SetMemoryRequestToLimit: false,
|
||||
},
|
||||
specSchedule: "30 00 * * 7",
|
||||
expectedSchedule: "30 00 * * 7",
|
||||
expectedJobName: "lb-acid-test-cluster",
|
||||
expectedResources: acidv1.Resources{
|
||||
ResourceRequests: acidv1.ResourceDescription{CPU: "10m", Memory: "50Mi"},
|
||||
ResourceLimits: acidv1.ResourceDescription{CPU: "300m", Memory: "300Mi"},
|
||||
},
|
||||
},
|
||||
{
|
||||
subTest: "test generation of logical backup pod resources when partly configured",
|
||||
config: config.Config{
|
||||
LogicalBackup: config.LogicalBackup{
|
||||
LogicalBackupCPURequest: "50m",
|
||||
LogicalBackupCPULimit: "250m",
|
||||
LogicalBackupJobPrefix: "",
|
||||
LogicalBackupSchedule: "30 00 * * *",
|
||||
},
|
||||
Resources: configResources,
|
||||
PodManagementPolicy: "ordered_ready",
|
||||
SetMemoryRequestToLimit: false,
|
||||
},
|
||||
specSchedule: "",
|
||||
expectedSchedule: "30 00 * * *",
|
||||
expectedJobName: "acid-test-cluster",
|
||||
expectedResources: acidv1.Resources{
|
||||
ResourceRequests: acidv1.ResourceDescription{CPU: "50m", Memory: "100Mi"},
|
||||
ResourceLimits: acidv1.ResourceDescription{CPU: "250m", Memory: "500Mi"},
|
||||
},
|
||||
},
|
||||
{
|
||||
subTest: "test generation of logical backup pod resources with SetMemoryRequestToLimit enabled",
|
||||
config: config.Config{
|
||||
LogicalBackup: config.LogicalBackup{
|
||||
LogicalBackupMemoryRequest: "80Mi",
|
||||
LogicalBackupMemoryLimit: "200Mi",
|
||||
LogicalBackupJobPrefix: "test-long-prefix-so-name-must-be-trimmed-",
|
||||
LogicalBackupSchedule: "30 00 * * *",
|
||||
},
|
||||
Resources: configResources,
|
||||
PodManagementPolicy: "ordered_ready",
|
||||
SetMemoryRequestToLimit: true,
|
||||
},
|
||||
specSchedule: "",
|
||||
expectedSchedule: "30 00 * * *",
|
||||
expectedJobName: "test-long-prefix-so-name-must-be-trimmed-acid-test-c",
|
||||
expectedResources: acidv1.Resources{
|
||||
ResourceRequests: acidv1.ResourceDescription{CPU: "100m", Memory: "200Mi"},
|
||||
ResourceLimits: acidv1.ResourceDescription{CPU: "1", Memory: "200Mi"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
var cluster = New(
|
||||
Config{
|
||||
OpConfig: tt.config,
|
||||
}, k8sutil.NewMockKubernetesClient(), acidv1.Postgresql{}, logger, eventRecorder)
|
||||
|
||||
cluster.ObjectMeta.Name = clusterName
|
||||
cluster.Spec.LogicalBackupSchedule = tt.specSchedule
|
||||
cronJob, err := cluster.generateLogicalBackupJob()
|
||||
assert.NoError(t, err)
|
||||
|
||||
if cronJob.Spec.Schedule != tt.expectedSchedule {
|
||||
t.Errorf("%s - %s: expected schedule %s, got %s", t.Name(), tt.subTest, tt.expectedSchedule, cronJob.Spec.Schedule)
|
||||
}
|
||||
|
||||
if cronJob.Name != tt.expectedJobName {
|
||||
t.Errorf("%s - %s: expected job name %s, got %s", t.Name(), tt.subTest, tt.expectedJobName, cronJob.Name)
|
||||
}
|
||||
|
||||
containers := cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers
|
||||
clusterResources, err := parseResourceRequirements(containers[0].Resources)
|
||||
assert.NoError(t, err)
|
||||
if !reflect.DeepEqual(tt.expectedResources, clusterResources) {
|
||||
t.Errorf("%s - %s: expected resources %#v, got %#v", t.Name(), tt.subTest, tt.expectedResources, clusterResources)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateCapabilities(t *testing.T) {
|
||||
tests := []struct {
|
||||
subTest string
|
||||
|
||||
@@ -2,7 +2,6 @@ package cluster
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"context"
|
||||
@@ -389,7 +388,7 @@ func TestUpdateFabricEventStream(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
result := cluster.generateFabricEventStream(appId)
|
||||
if !reflect.DeepEqual(result.Spec.EventStreams, streams.Items[0].Spec.EventStreams) {
|
||||
if match, _ := sameStreams(streams.Items[0].Spec.EventStreams, result.Spec.EventStreams); !match {
|
||||
t.Errorf("Malformed FabricEventStream, expected %#v, got %#v", streams.Items[0], result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,9 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||
result.LogicalBackupSchedule = util.Coalesce(fromCRD.LogicalBackup.Schedule, "30 00 * * *")
|
||||
result.LogicalBackupDockerImage = util.Coalesce(fromCRD.LogicalBackup.DockerImage, "registry.opensource.zalan.do/acid/logical-backup:v1.8.2")
|
||||
result.LogicalBackupProvider = util.Coalesce(fromCRD.LogicalBackup.BackupProvider, "s3")
|
||||
result.LogicalBackupAzureStorageAccountName = fromCRD.LogicalBackup.AzureStorageAccountName
|
||||
result.LogicalBackupAzureStorageAccountKey = fromCRD.LogicalBackup.AzureStorageAccountKey
|
||||
result.LogicalBackupAzureStorageContainer = fromCRD.LogicalBackup.AzureStorageContainer
|
||||
result.LogicalBackupS3Bucket = fromCRD.LogicalBackup.S3Bucket
|
||||
result.LogicalBackupS3Region = fromCRD.LogicalBackup.S3Region
|
||||
result.LogicalBackupS3Endpoint = fromCRD.LogicalBackup.S3Endpoint
|
||||
@@ -183,9 +186,10 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||
result.LogicalBackupS3RetentionTime = fromCRD.LogicalBackup.RetentionTime
|
||||
result.LogicalBackupGoogleApplicationCredentials = fromCRD.LogicalBackup.GoogleApplicationCredentials
|
||||
result.LogicalBackupJobPrefix = util.Coalesce(fromCRD.LogicalBackup.JobPrefix, "logical-backup-")
|
||||
result.LogicalBackupAzureStorageAccountName = fromCRD.LogicalBackup.AzureStorageAccountName
|
||||
result.LogicalBackupAzureStorageAccountKey = fromCRD.LogicalBackup.AzureStorageAccountKey
|
||||
result.LogicalBackupAzureStorageContainer = fromCRD.LogicalBackup.AzureStorageContainer
|
||||
result.LogicalBackupCPURequest = fromCRD.LogicalBackup.CPURequest
|
||||
result.LogicalBackupMemoryRequest = fromCRD.LogicalBackup.MemoryRequest
|
||||
result.LogicalBackupCPULimit = fromCRD.LogicalBackup.CPULimit
|
||||
result.LogicalBackupMemoryLimit = fromCRD.LogicalBackup.MemoryLimit
|
||||
|
||||
// debug config
|
||||
result.DebugLogging = fromCRD.OperatorDebug.DebugLogging
|
||||
|
||||
@@ -128,6 +128,9 @@ type LogicalBackup struct {
|
||||
LogicalBackupSchedule string `name:"logical_backup_schedule" default:"30 00 * * *"`
|
||||
LogicalBackupDockerImage string `name:"logical_backup_docker_image" default:"registry.opensource.zalan.do/acid/logical-backup:v1.8.2"`
|
||||
LogicalBackupProvider string `name:"logical_backup_provider" default:"s3"`
|
||||
LogicalBackupAzureStorageAccountName string `name:"logical_backup_azure_storage_account_name" default:""`
|
||||
LogicalBackupAzureStorageContainer string `name:"logical_backup_azure_storage_container" default:""`
|
||||
LogicalBackupAzureStorageAccountKey string `name:"logical_backup_azure_storage_account_key" default:""`
|
||||
LogicalBackupS3Bucket string `name:"logical_backup_s3_bucket" default:""`
|
||||
LogicalBackupS3Region string `name:"logical_backup_s3_region" default:""`
|
||||
LogicalBackupS3Endpoint string `name:"logical_backup_s3_endpoint" default:""`
|
||||
@@ -137,9 +140,10 @@ type LogicalBackup struct {
|
||||
LogicalBackupS3RetentionTime string `name:"logical_backup_s3_retention_time" default:""`
|
||||
LogicalBackupGoogleApplicationCredentials string `name:"logical_backup_google_application_credentials" default:""`
|
||||
LogicalBackupJobPrefix string `name:"logical_backup_job_prefix" default:"logical-backup-"`
|
||||
LogicalBackupAzureStorageAccountName string `name:"logical_backup_azure_storage_account_name" default:""`
|
||||
LogicalBackupAzureStorageContainer string `name:"logical_backup_azure_storage_container" default:""`
|
||||
LogicalBackupAzureStorageAccountKey string `name:"logical_backup_azure_storage_account_key" default:""`
|
||||
LogicalBackupCPURequest string `name:"logical_backup_cpu_request"`
|
||||
LogicalBackupMemoryRequest string `name:"logical_backup_memory_request"`
|
||||
LogicalBackupCPULimit string `name:"logical_backup_cpu_limit"`
|
||||
LogicalBackupMemoryLimit string `name:"logical_backup_memory_limit"`
|
||||
}
|
||||
|
||||
// Operator options for connection pooler
|
||||
|
||||
Reference in New Issue
Block a user