Merge branch 'master' into fix-critical-op-pdb-idle-alerts
This commit is contained in:
commit
3d1c115ef0
|
|
@ -81,8 +81,8 @@ spec:
|
||||||
"cost_memory": 0.014375,
|
"cost_memory": 0.014375,
|
||||||
"free_iops": 3000,
|
"free_iops": 3000,
|
||||||
"free_throughput": 125,
|
"free_throughput": 125,
|
||||||
"limit_iops": 16000,
|
"limit_iops": 80000,
|
||||||
"limit_throughput": 1000,
|
"limit_throughput": 2000,
|
||||||
"postgresql_versions": [
|
"postgresql_versions": [
|
||||||
"18",
|
"18",
|
||||||
"17",
|
"17",
|
||||||
|
|
|
||||||
|
|
@ -66,11 +66,6 @@ spec:
|
||||||
aws_region:
|
aws_region:
|
||||||
default: eu-central-1
|
default: eu-central-1
|
||||||
type: string
|
type: string
|
||||||
enable_ebs_gp3_migration:
|
|
||||||
type: boolean
|
|
||||||
enable_ebs_gp3_migration_max_size:
|
|
||||||
format: int64
|
|
||||||
type: integer
|
|
||||||
gcp_credentials:
|
gcp_credentials:
|
||||||
type: string
|
type: string
|
||||||
irsa_role_arn:
|
irsa_role_arn:
|
||||||
|
|
|
||||||
|
|
@ -3258,7 +3258,8 @@ spec:
|
||||||
description: Volume describes a single volume in the manifest.
|
description: Volume describes a single volume in the manifest.
|
||||||
properties:
|
properties:
|
||||||
iops:
|
iops:
|
||||||
format: int64
|
format: int32
|
||||||
|
maximum: 80000
|
||||||
type: integer
|
type: integer
|
||||||
isSubPathExpr:
|
isSubPathExpr:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
@ -3319,7 +3320,8 @@ spec:
|
||||||
subPath:
|
subPath:
|
||||||
type: string
|
type: string
|
||||||
throughput:
|
throughput:
|
||||||
format: int64
|
format: int32
|
||||||
|
maximum: 2000
|
||||||
type: integer
|
type: integer
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
|
|
|
||||||
|
|
@ -350,16 +350,12 @@ configAwsOrGcp:
|
||||||
# AWS region used to store EBS volumes
|
# AWS region used to store EBS volumes
|
||||||
aws_region: eu-central-1
|
aws_region: eu-central-1
|
||||||
|
|
||||||
# enable automatic migration on AWS from gp2 to gp3 volumes
|
|
||||||
enable_ebs_gp3_migration: false
|
|
||||||
# defines maximum volume size in GB until which auto migration happens
|
|
||||||
# enable_ebs_gp3_migration_max_size: 1000
|
|
||||||
|
|
||||||
# GCP credentials that will be used by the operator / pods
|
# GCP credentials that will be used by the operator / pods
|
||||||
# gcp_credentials: ""
|
# gcp_credentials: ""
|
||||||
|
|
||||||
# AWS IAM role to supply in the iam.amazonaws.com/role annotation of Postgres pods
|
# AWS IAM role to supply in the iam.amazonaws.com/role annotation of Postgres pods
|
||||||
# kube_iam_role: ""
|
# kube_iam_role: ""
|
||||||
|
|
||||||
# Full ARN for IRSA (IAM Roles for Service Accounts) on EKS
|
# Full ARN for IRSA (IAM Roles for Service Accounts) on EKS
|
||||||
# irsa_role_arn: ""
|
# irsa_role_arn: ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -554,11 +554,11 @@ properties of the persistent storage that stores Postgres data.
|
||||||
|
|
||||||
* **iops**
|
* **iops**
|
||||||
When running the operator on AWS the latest generation of EBS volumes (`gp3`)
|
When running the operator on AWS the latest generation of EBS volumes (`gp3`)
|
||||||
allows for configuring the number of IOPS. Maximum is 16000. Optional.
|
allows for configuring the number of IOPS. Maximum is 80000. Optional.
|
||||||
|
|
||||||
* **throughput**
|
* **throughput**
|
||||||
When running the operator on AWS the latest generation of EBS volumes (`gp3`)
|
When running the operator on AWS the latest generation of EBS volumes (`gp3`)
|
||||||
allows for configuring the throughput in MB/s. Maximum is 1000. Optional.
|
allows for configuring the throughput in MB/s. Maximum is 2000. Optional.
|
||||||
|
|
||||||
* **selector**
|
* **selector**
|
||||||
A label query over PVs to consider for binding. See the [Kubernetes
|
A label query over PVs to consider for binding. See the [Kubernetes
|
||||||
|
|
|
||||||
|
|
@ -582,7 +582,7 @@ configuration they are grouped under the `kubernetes` key.
|
||||||
1. `ebs` : operator resizes EBS volumes directly and executes `resizefs` within a pod
|
1. `ebs` : operator resizes EBS volumes directly and executes `resizefs` within a pod
|
||||||
2. `pvc` : operator only changes PVC definition
|
2. `pvc` : operator only changes PVC definition
|
||||||
3. `off` : disables resize of the volumes.
|
3. `off` : disables resize of the volumes.
|
||||||
4. `mixed` : operator uses AWS API to adjust size, throughput, and IOPS, and calls pvc change for file system resize
|
4. `mixed` : operator uses AWS API to adjust size, type, throughput, and IOPS, and calls pvc change for file system resize
|
||||||
Default is "pvc".
|
Default is "pvc".
|
||||||
|
|
||||||
## Kubernetes resource requests
|
## Kubernetes resource requests
|
||||||
|
|
@ -821,16 +821,6 @@ yet officially supported.
|
||||||
Path to mount the above Secret in the filesystem of the container(s).
|
Path to mount the above Secret in the filesystem of the container(s).
|
||||||
The default is empty.
|
The default is empty.
|
||||||
|
|
||||||
* **enable_ebs_gp3_migration**
|
|
||||||
enable automatic migration on AWS from gp2 to gp3 volumes, that are smaller
|
|
||||||
than the configured max size (see below). This ignores that EBS gp3 is by
|
|
||||||
default only 125 MB/sec vs 250 MB/sec for gp2 >= 333GB.
|
|
||||||
The default is `false`.
|
|
||||||
|
|
||||||
* **enable_ebs_gp3_migration_max_size**
|
|
||||||
defines the maximum volume size in GB until which auto migration happens.
|
|
||||||
Default is 1000 (1TB) which matches 3000 IOPS.
|
|
||||||
|
|
||||||
## Logical backup
|
## Logical backup
|
||||||
|
|
||||||
These parameters configure a K8s cron job managed by the operator to produce
|
These parameters configure a K8s cron job managed by the operator to produce
|
||||||
|
|
|
||||||
|
|
@ -1129,7 +1129,7 @@ When using AWS with gp3 volumes you should set the mode to `mixed` because it
|
||||||
will also adjust the IOPS and throughput that can be defined in the manifest.
|
will also adjust the IOPS and throughput that can be defined in the manifest.
|
||||||
Check the [AWS docs](https://aws.amazon.com/ebs/general-purpose/) to learn
|
Check the [AWS docs](https://aws.amazon.com/ebs/general-purpose/) to learn
|
||||||
about default and maximum values. Keep in mind that AWS rate-limits updating
|
about default and maximum values. Keep in mind that AWS rate-limits updating
|
||||||
volume specs to no more than once every 6 hours.
|
volume specs to no more than 4 times within 24 hours.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
spec:
|
spec:
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ spec:
|
||||||
volume:
|
volume:
|
||||||
size: 1Gi
|
size: 1Gi
|
||||||
# storageClass: my-sc
|
# storageClass: my-sc
|
||||||
# iops: 1000 # for EBS gp3
|
# iops: 1000
|
||||||
# throughput: 250 # in MB/s for EBS gp3
|
# throughput: 250 # in MB/s
|
||||||
# selector:
|
# selector:
|
||||||
# matchExpressions:
|
# matchExpressions:
|
||||||
# - { key: flavour, operator: In, values: [ "banana", "chocolate" ] }
|
# - { key: flavour, operator: In, values: [ "banana", "chocolate" ] }
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,6 @@ data:
|
||||||
enable_cross_namespace_secret: "false"
|
enable_cross_namespace_secret: "false"
|
||||||
enable_finalizers: "false"
|
enable_finalizers: "false"
|
||||||
enable_database_access: "true"
|
enable_database_access: "true"
|
||||||
enable_ebs_gp3_migration: "false"
|
|
||||||
enable_ebs_gp3_migration_max_size: "1000"
|
|
||||||
enable_init_containers: "true"
|
enable_init_containers: "true"
|
||||||
enable_lazy_spilo_upgrade: "false"
|
enable_lazy_spilo_upgrade: "false"
|
||||||
enable_maintenance_windows: "true"
|
enable_maintenance_windows: "true"
|
||||||
|
|
|
||||||
|
|
@ -66,11 +66,6 @@ spec:
|
||||||
aws_region:
|
aws_region:
|
||||||
default: eu-central-1
|
default: eu-central-1
|
||||||
type: string
|
type: string
|
||||||
enable_ebs_gp3_migration:
|
|
||||||
type: boolean
|
|
||||||
enable_ebs_gp3_migration_max_size:
|
|
||||||
format: int64
|
|
||||||
type: integer
|
|
||||||
gcp_credentials:
|
gcp_credentials:
|
||||||
type: string
|
type: string
|
||||||
irsa_role_arn:
|
irsa_role_arn:
|
||||||
|
|
|
||||||
|
|
@ -167,8 +167,6 @@ configuration:
|
||||||
# additional_secret_mount: "some-secret-name"
|
# additional_secret_mount: "some-secret-name"
|
||||||
# additional_secret_mount_path: "/some/dir"
|
# additional_secret_mount_path: "/some/dir"
|
||||||
aws_region: eu-central-1
|
aws_region: eu-central-1
|
||||||
enable_ebs_gp3_migration: false
|
|
||||||
# enable_ebs_gp3_migration_max_size: 1000
|
|
||||||
# gcp_credentials: ""
|
# gcp_credentials: ""
|
||||||
# kube_iam_role: ""
|
# kube_iam_role: ""
|
||||||
# irsa_role_arn: ""
|
# irsa_role_arn: ""
|
||||||
|
|
|
||||||
|
|
@ -3258,7 +3258,8 @@ spec:
|
||||||
description: Volume describes a single volume in the manifest.
|
description: Volume describes a single volume in the manifest.
|
||||||
properties:
|
properties:
|
||||||
iops:
|
iops:
|
||||||
format: int64
|
format: int32
|
||||||
|
maximum: 80000
|
||||||
type: integer
|
type: integer
|
||||||
isSubPathExpr:
|
isSubPathExpr:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
@ -3319,7 +3320,8 @@ spec:
|
||||||
subPath:
|
subPath:
|
||||||
type: string
|
type: string
|
||||||
throughput:
|
throughput:
|
||||||
format: int64
|
format: int32
|
||||||
|
maximum: 2000
|
||||||
type: integer
|
type: integer
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
|
|
|
||||||
|
|
@ -246,17 +246,15 @@ type LoadBalancerConfiguration struct {
|
||||||
type AWSGCPConfiguration struct {
|
type AWSGCPConfiguration struct {
|
||||||
WALES3Bucket string `json:"wal_s3_bucket,omitempty"`
|
WALES3Bucket string `json:"wal_s3_bucket,omitempty"`
|
||||||
// +kubebuilder:default=eu-central-1
|
// +kubebuilder:default=eu-central-1
|
||||||
AWSRegion string `json:"aws_region,omitempty"`
|
AWSRegion string `json:"aws_region,omitempty"`
|
||||||
WALGSBucket string `json:"wal_gs_bucket,omitempty"`
|
WALGSBucket string `json:"wal_gs_bucket,omitempty"`
|
||||||
GCPCredentials string `json:"gcp_credentials,omitempty"`
|
GCPCredentials string `json:"gcp_credentials,omitempty"`
|
||||||
WALAZStorageAccount string `json:"wal_az_storage_account,omitempty"`
|
WALAZStorageAccount string `json:"wal_az_storage_account,omitempty"`
|
||||||
LogS3Bucket string `json:"log_s3_bucket,omitempty"`
|
LogS3Bucket string `json:"log_s3_bucket,omitempty"`
|
||||||
KubeIAMRole string `json:"kube_iam_role,omitempty"`
|
KubeIAMRole string `json:"kube_iam_role,omitempty"`
|
||||||
IRSARoleARN string `json:"irsa_role_arn,omitempty"`
|
IRSARoleARN string `json:"irsa_role_arn,omitempty"`
|
||||||
AdditionalSecretMount string `json:"additional_secret_mount,omitempty"`
|
AdditionalSecretMount string `json:"additional_secret_mount,omitempty"`
|
||||||
AdditionalSecretMountPath string `json:"additional_secret_mount_path,omitempty"`
|
AdditionalSecretMountPath string `json:"additional_secret_mount_path,omitempty"`
|
||||||
EnableEBSGp3Migration bool `json:"enable_ebs_gp3_migration,omitempty"`
|
|
||||||
EnableEBSGp3MigrationMaxSize int64 `json:"enable_ebs_gp3_migration_max_size,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OperatorDebugConfiguration defines options for the debug mode
|
// OperatorDebugConfiguration defines options for the debug mode
|
||||||
|
|
|
||||||
|
|
@ -66,11 +66,6 @@ spec:
|
||||||
aws_region:
|
aws_region:
|
||||||
default: eu-central-1
|
default: eu-central-1
|
||||||
type: string
|
type: string
|
||||||
enable_ebs_gp3_migration:
|
|
||||||
type: boolean
|
|
||||||
enable_ebs_gp3_migration_max_size:
|
|
||||||
format: int64
|
|
||||||
type: integer
|
|
||||||
gcp_credentials:
|
gcp_credentials:
|
||||||
type: string
|
type: string
|
||||||
irsa_role_arn:
|
irsa_role_arn:
|
||||||
|
|
|
||||||
|
|
@ -3258,7 +3258,8 @@ spec:
|
||||||
description: Volume describes a single volume in the manifest.
|
description: Volume describes a single volume in the manifest.
|
||||||
properties:
|
properties:
|
||||||
iops:
|
iops:
|
||||||
format: int64
|
format: int32
|
||||||
|
maximum: 80000
|
||||||
type: integer
|
type: integer
|
||||||
isSubPathExpr:
|
isSubPathExpr:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
@ -3319,7 +3320,8 @@ spec:
|
||||||
subPath:
|
subPath:
|
||||||
type: string
|
type: string
|
||||||
throughput:
|
throughput:
|
||||||
format: int64
|
format: int32
|
||||||
|
maximum: 2000
|
||||||
type: integer
|
type: integer
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
|
|
|
||||||
|
|
@ -167,9 +167,11 @@ type Volume struct {
|
||||||
StorageClass string `json:"storageClass,omitempty"`
|
StorageClass string `json:"storageClass,omitempty"`
|
||||||
SubPath string `json:"subPath,omitempty"`
|
SubPath string `json:"subPath,omitempty"`
|
||||||
IsSubPathExpr *bool `json:"isSubPathExpr,omitempty"`
|
IsSubPathExpr *bool `json:"isSubPathExpr,omitempty"`
|
||||||
Iops *int64 `json:"iops,omitempty"`
|
// +kubebuilder:validation:Maximum=80000
|
||||||
Throughput *int64 `json:"throughput,omitempty"`
|
Iops *int32 `json:"iops,omitempty"`
|
||||||
VolumeType string `json:"type,omitempty"`
|
// +kubebuilder:validation:Maximum=2000
|
||||||
|
Throughput *int32 `json:"throughput,omitempty"`
|
||||||
|
VolumeType string `json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdditionalVolume specs additional optional volumes for statefulset
|
// AdditionalVolume specs additional optional volumes for statefulset
|
||||||
|
|
|
||||||
|
|
@ -1686,12 +1686,12 @@ func (in *Volume) DeepCopyInto(out *Volume) {
|
||||||
}
|
}
|
||||||
if in.Iops != nil {
|
if in.Iops != nil {
|
||||||
in, out := &in.Iops, &out.Iops
|
in, out := &in.Iops, &out.Iops
|
||||||
*out = new(int64)
|
*out = new(int32)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
if in.Throughput != nil {
|
if in.Throughput != nil {
|
||||||
in, out := &in.Throughput, &out.Throughput
|
in, out := &in.Throughput, &out.Throughput
|
||||||
*out = new(int64)
|
*out = new(int32)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ func New(cfg Config, kubeClient k8sutil.KubernetesClient, pgSpec acidv1.Postgres
|
||||||
cluster.eventRecorder = eventRecorder
|
cluster.eventRecorder = eventRecorder
|
||||||
|
|
||||||
cluster.EBSVolumes = make(map[string]volumes.VolumeProperties)
|
cluster.EBSVolumes = make(map[string]volumes.VolumeProperties)
|
||||||
if cfg.OpConfig.StorageResizeMode != "pvc" || cfg.OpConfig.EnableEBSGp3Migration {
|
if cfg.OpConfig.StorageResizeMode != "pvc" {
|
||||||
cluster.VolumeResizer = &volumes.EBSVolumeResizer{AWSRegion: cfg.OpConfig.AWSRegion}
|
cluster.VolumeResizer = &volumes.EBSVolumeResizer{AWSRegion: cfg.OpConfig.AWSRegion}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,18 +95,10 @@ func (c *Cluster) Sync(newSpec *acidv1.Postgresql) error {
|
||||||
c.logger.Errorf("could not sync Patroni resources: %v", err)
|
c.logger.Errorf("could not sync Patroni resources: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync volume may already transition volumes to gp3, if iops/throughput or type is specified
|
|
||||||
if err = c.syncVolumes(); err != nil {
|
if err = c.syncVolumes(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.OpConfig.EnableEBSGp3Migration && len(c.EBSVolumes) > 0 {
|
|
||||||
err = c.executeEBSMigration()
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.syncPodServiceAccount(); err != nil {
|
if err = c.syncPodServiceAccount(); err != nil {
|
||||||
c.logger.Errorf("could not sync pod service account: %v", err)
|
c.logger.Errorf("could not sync pod service account: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1811,7 +1803,6 @@ func (c *Cluster) syncLogicalBackupJob() error {
|
||||||
// no existing logical backup job, create new one
|
// no existing logical backup job, create new one
|
||||||
c.logger.Info("could not find the cluster's logical backup job")
|
c.logger.Info("could not find the cluster's logical backup job")
|
||||||
|
|
||||||
|
|
||||||
if err = c.createLogicalBackupJob(); err == nil {
|
if err = c.createLogicalBackupJob(); err == nil {
|
||||||
c.logger.Infof("created missing logical backup job %s", jobName)
|
c.logger.Infof("created missing logical backup job %s", jobName)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
|
||||||
"github.com/zalando/postgres-operator/pkg/spec"
|
"github.com/zalando/postgres-operator/pkg/spec"
|
||||||
"github.com/zalando/postgres-operator/pkg/util/constants"
|
"github.com/zalando/postgres-operator/pkg/util/constants"
|
||||||
"github.com/zalando/postgres-operator/pkg/util/filesystems"
|
"github.com/zalando/postgres-operator/pkg/util/filesystems"
|
||||||
|
|
@ -79,47 +78,35 @@ func (c *Cluster) syncUnderlyingEBSVolume() error {
|
||||||
}
|
}
|
||||||
targetSize := quantityToGigabyte(newSize)
|
targetSize := quantityToGigabyte(newSize)
|
||||||
|
|
||||||
awsGp3 := aws.String("gp3")
|
|
||||||
awsIo2 := aws.String("io2")
|
|
||||||
|
|
||||||
errors := make([]string, 0)
|
errors := make([]string, 0)
|
||||||
|
|
||||||
for _, volume := range c.EBSVolumes {
|
for _, volume := range c.EBSVolumes {
|
||||||
var modifyIops *int64
|
var modifyIops *int32
|
||||||
var modifyThroughput *int64
|
var modifyThroughput *int32
|
||||||
var modifySize *int64
|
var modifySize *int32
|
||||||
var modifyType *string
|
var modifyType *string
|
||||||
|
|
||||||
if targetValue.Iops != nil && *targetValue.Iops >= int64(3000) {
|
if targetValue.Iops != nil && *targetValue.Iops >= int32(3000) {
|
||||||
if volume.Iops != int64(*targetValue.Iops) {
|
if volume.Iops != int32(*targetValue.Iops) {
|
||||||
modifyIops = targetValue.Iops
|
modifyIops = targetValue.Iops
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetValue.Throughput != nil && *targetValue.Throughput >= int64(125) {
|
if targetValue.Throughput != nil && *targetValue.Throughput >= int32(125) {
|
||||||
if volume.Throughput != int64(*targetValue.Throughput) {
|
if volume.Throughput != int32(*targetValue.Throughput) {
|
||||||
modifyThroughput = targetValue.Throughput
|
modifyThroughput = targetValue.Throughput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetSize > int64(volume.Size) {
|
if targetSize > volume.Size {
|
||||||
modifySize = &targetSize
|
modifySize = &targetSize
|
||||||
}
|
}
|
||||||
|
|
||||||
if modifyIops != nil || modifyThroughput != nil || modifySize != nil {
|
if targetValue.VolumeType != "" && targetValue.VolumeType != volume.VolumeType {
|
||||||
if modifyIops != nil || modifyThroughput != nil {
|
modifyType = &targetValue.VolumeType
|
||||||
// we default to gp3 if iops and throughput are configured
|
}
|
||||||
modifyType = awsGp3
|
|
||||||
if targetValue.VolumeType == "io2" {
|
|
||||||
modifyType = awsIo2
|
|
||||||
}
|
|
||||||
} else if targetValue.VolumeType == "gp3" && volume.VolumeType != "gp3" {
|
|
||||||
modifyType = awsGp3
|
|
||||||
} else {
|
|
||||||
// do not touch type
|
|
||||||
modifyType = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if modifyIops != nil || modifyThroughput != nil || modifySize != nil || modifyType != nil {
|
||||||
err = c.VolumeResizer.ModifyVolume(volume.VolumeID, modifyType, modifySize, modifyIops, modifyThroughput)
|
err = c.VolumeResizer.ModifyVolume(volume.VolumeID, modifyType, modifySize, modifyIops, modifyThroughput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors = append(errors, fmt.Sprintf("modify failed: %v, showing current EBS values: volume-id=%s size=%d iops=%d throughput=%d", err, volume.VolumeID, volume.Size, volume.Iops, volume.Throughput))
|
errors = append(errors, fmt.Sprintf("modify failed: %v, showing current EBS values: volume-id=%s size=%d iops=%d throughput=%d", err, volume.VolumeID, volume.Size, volume.Iops, volume.Throughput))
|
||||||
|
|
@ -450,50 +437,6 @@ func getPodNameFromPersistentVolume(pv *v1.PersistentVolume) *spec.NamespacedNam
|
||||||
return &spec.NamespacedName{Namespace: namespace, Name: name}
|
return &spec.NamespacedName{Namespace: namespace, Name: name}
|
||||||
}
|
}
|
||||||
|
|
||||||
func quantityToGigabyte(q resource.Quantity) int64 {
|
func quantityToGigabyte(q resource.Quantity) int32 {
|
||||||
return q.ScaledValue(0) / (1 * constants.Gigabyte)
|
return int32(q.ScaledValue(0) / (1 * constants.Gigabyte))
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cluster) executeEBSMigration() error {
|
|
||||||
pvs, err := c.listPersistentVolumes()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not list persistent volumes: %v", err)
|
|
||||||
}
|
|
||||||
if len(pvs) == 0 {
|
|
||||||
c.logger.Warningf("no persistent volumes found - skipping EBS migration")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
c.logger.Debugf("found %d volumes, size of known volumes %d", len(pvs), len(c.EBSVolumes))
|
|
||||||
|
|
||||||
if len(pvs) == len(c.EBSVolumes) {
|
|
||||||
hasGp2 := false
|
|
||||||
for _, v := range c.EBSVolumes {
|
|
||||||
if v.VolumeType == "gp2" {
|
|
||||||
hasGp2 = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasGp2 {
|
|
||||||
c.logger.Debugf("no EBS gp2 volumes left to migrate")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var i3000 int64 = 3000
|
|
||||||
var i125 int64 = 125
|
|
||||||
|
|
||||||
for _, volume := range c.EBSVolumes {
|
|
||||||
if volume.VolumeType == "gp2" && volume.Size < c.OpConfig.EnableEBSGp3MigrationMaxSize {
|
|
||||||
c.logger.Infof("modifying EBS volume %s to type gp3 migration (%d)", volume.VolumeID, volume.Size)
|
|
||||||
err = c.VolumeResizer.ModifyVolume(volume.VolumeID, aws.String("gp3"), &volume.Size, &i3000, &i125)
|
|
||||||
if nil != err {
|
|
||||||
c.logger.Warningf("modifying volume %s failed: %v", volume.VolumeID, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c.logger.Debugf("skipping EBS volume %s to type gp3 migration (%d)", volume.VolumeID, volume.Size)
|
|
||||||
}
|
|
||||||
c.EBSVolumes[volume.VolumeID] = volume
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import (
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/zalando/postgres-operator/mocks"
|
"github.com/zalando/postgres-operator/mocks"
|
||||||
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||||
|
|
@ -25,9 +24,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type testVolume struct {
|
type testVolume struct {
|
||||||
size int64
|
size int32
|
||||||
iops int64
|
iops int32
|
||||||
throughtput int64
|
throughtput int32
|
||||||
volType string
|
volType string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,7 +120,7 @@ func TestQuantityToGigabyte(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
quantityStr string
|
quantityStr string
|
||||||
expected int64
|
expected int32
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"test with 1Gi",
|
"test with 1Gi",
|
||||||
|
|
@ -131,12 +130,12 @@ func TestQuantityToGigabyte(t *testing.T) {
|
||||||
{
|
{
|
||||||
"test with float",
|
"test with float",
|
||||||
"1.5Gi",
|
"1.5Gi",
|
||||||
int64(1),
|
int32(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"test with 1000Mi",
|
"test with 1000Mi",
|
||||||
"1000Mi",
|
"1000Mi",
|
||||||
int64(0),
|
int32(0),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,64 +178,6 @@ func CreatePVCs(namespace string, clusterName string, labels labels.Set, n int,
|
||||||
return pvcList
|
return pvcList
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMigrateEBS(t *testing.T) {
|
|
||||||
client, _ := newFakeK8sPVCclient()
|
|
||||||
clusterName := "acid-test-cluster"
|
|
||||||
namespace := "default"
|
|
||||||
|
|
||||||
// new cluster with pvc storage resize mode and configured labels
|
|
||||||
var cluster = New(
|
|
||||||
Config{
|
|
||||||
OpConfig: config.Config{
|
|
||||||
Resources: config.Resources{
|
|
||||||
ClusterLabels: map[string]string{"application": "spilo"},
|
|
||||||
ClusterNameLabel: "cluster-name",
|
|
||||||
},
|
|
||||||
StorageResizeMode: "pvc",
|
|
||||||
EnableEBSGp3Migration: true,
|
|
||||||
EnableEBSGp3MigrationMaxSize: 1000,
|
|
||||||
},
|
|
||||||
}, client, acidv1.Postgresql{}, logger, eventRecorder)
|
|
||||||
cluster.Spec.Volume.Size = "1Gi"
|
|
||||||
|
|
||||||
// set metadata, so that labels will get correct values
|
|
||||||
cluster.Name = clusterName
|
|
||||||
cluster.Namespace = namespace
|
|
||||||
filterLabels := cluster.labelsSet(false)
|
|
||||||
|
|
||||||
testVolumes := []testVolume{testVol, testVol}
|
|
||||||
|
|
||||||
initTestVolumesAndPods(cluster.KubeClient, namespace, clusterName, filterLabels, testVolumes)
|
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
resizer := mocks.NewMockVolumeResizer(ctrl)
|
|
||||||
|
|
||||||
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-1")).Return("ebs-volume-1", nil)
|
|
||||||
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil)
|
|
||||||
|
|
||||||
resizer.EXPECT().GetProviderVolumeID(gomock.Any()).
|
|
||||||
DoAndReturn(func(pv *v1.PersistentVolume) (string, error) {
|
|
||||||
return resizer.ExtractVolumeID(pv.Spec.AWSElasticBlockStore.VolumeID)
|
|
||||||
}).
|
|
||||||
Times(2)
|
|
||||||
|
|
||||||
resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2"})).Return(
|
|
||||||
[]volumes.VolumeProperties{
|
|
||||||
{VolumeID: "ebs-volume-1", VolumeType: "gp2", Size: 100},
|
|
||||||
{VolumeID: "ebs-volume-2", VolumeType: "gp3", Size: 100}}, nil)
|
|
||||||
|
|
||||||
// expect only gp2 volume to be modified
|
|
||||||
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Eq(aws.String("gp3")), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
|
|
||||||
|
|
||||||
cluster.VolumeResizer = resizer
|
|
||||||
err := cluster.populateVolumeMetaData()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
err = cluster.executeEBSMigration()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initTestVolumesAndPods(client k8sutil.KubernetesClient, namespace, clustername string, labels labels.Set, volumes []testVolume) {
|
func initTestVolumesAndPods(client k8sutil.KubernetesClient, namespace, clustername string, labels labels.Set, volumes []testVolume) {
|
||||||
i := 0
|
i := 0
|
||||||
for _, v := range volumes {
|
for _, v := range volumes {
|
||||||
|
|
@ -287,7 +228,7 @@ func initTestVolumesAndPods(client k8sutil.KubernetesClient, namespace, clustern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMigrateGp3Support(t *testing.T) {
|
func TestGp2Gp3Migration(t *testing.T) {
|
||||||
client, _ := newFakeK8sPVCclient()
|
client, _ := newFakeK8sPVCclient()
|
||||||
clusterName := "acid-test-cluster"
|
clusterName := "acid-test-cluster"
|
||||||
namespace := "default"
|
namespace := "default"
|
||||||
|
|
@ -300,77 +241,13 @@ func TestMigrateGp3Support(t *testing.T) {
|
||||||
ClusterLabels: map[string]string{"application": "spilo"},
|
ClusterLabels: map[string]string{"application": "spilo"},
|
||||||
ClusterNameLabel: "cluster-name",
|
ClusterNameLabel: "cluster-name",
|
||||||
},
|
},
|
||||||
StorageResizeMode: "mixed",
|
StorageResizeMode: "mixed",
|
||||||
EnableEBSGp3Migration: false,
|
|
||||||
EnableEBSGp3MigrationMaxSize: 1000,
|
|
||||||
},
|
},
|
||||||
}, client, acidv1.Postgresql{}, logger, eventRecorder)
|
}, client, acidv1.Postgresql{Spec: acidv1.PostgresSpec{Volume: acidv1.Volume{VolumeType: "gp3"}}}, logger, eventRecorder)
|
||||||
|
|
||||||
cluster.Spec.Volume.Size = "150Gi"
|
cluster.Spec.Volume.Size = "150Gi"
|
||||||
cluster.Spec.Volume.Iops = aws.Int64(6000)
|
cluster.Spec.Volume.Iops = aws.Int32(6000)
|
||||||
cluster.Spec.Volume.Throughput = aws.Int64(275)
|
cluster.Spec.Volume.Throughput = aws.Int32(275)
|
||||||
|
|
||||||
// set metadata, so that labels will get correct values
|
|
||||||
cluster.Name = clusterName
|
|
||||||
cluster.Namespace = namespace
|
|
||||||
filterLabels := cluster.labelsSet(false)
|
|
||||||
|
|
||||||
testVolumes := []testVolume{testVol, testVol, testVol}
|
|
||||||
|
|
||||||
initTestVolumesAndPods(cluster.KubeClient, namespace, clusterName, filterLabels, testVolumes)
|
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
resizer := mocks.NewMockVolumeResizer(ctrl)
|
|
||||||
|
|
||||||
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-1")).Return("ebs-volume-1", nil)
|
|
||||||
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil)
|
|
||||||
resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-3")).Return("ebs-volume-3", nil)
|
|
||||||
|
|
||||||
resizer.EXPECT().GetProviderVolumeID(gomock.Any()).
|
|
||||||
DoAndReturn(func(pv *v1.PersistentVolume) (string, error) {
|
|
||||||
return resizer.ExtractVolumeID(pv.Spec.AWSElasticBlockStore.VolumeID)
|
|
||||||
}).
|
|
||||||
Times(3)
|
|
||||||
|
|
||||||
resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2", "ebs-volume-3"})).Return(
|
|
||||||
[]volumes.VolumeProperties{
|
|
||||||
{VolumeID: "ebs-volume-1", VolumeType: "gp3", Size: 100, Iops: 3000},
|
|
||||||
{VolumeID: "ebs-volume-2", VolumeType: "gp3", Size: 105, Iops: 4000},
|
|
||||||
{VolumeID: "ebs-volume-3", VolumeType: "gp3", Size: 151, Iops: 6000, Throughput: 275}}, nil)
|
|
||||||
|
|
||||||
// expect only gp2 volume to be modified
|
|
||||||
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Eq(aws.String("gp3")), gomock.Eq(aws.Int64(150)), gomock.Eq(aws.Int64(6000)), gomock.Eq(aws.Int64(275))).Return(nil)
|
|
||||||
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-2"), gomock.Eq(aws.String("gp3")), gomock.Eq(aws.Int64(150)), gomock.Eq(aws.Int64(6000)), gomock.Eq(aws.Int64(275))).Return(nil)
|
|
||||||
// resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-3"), gomock.Eq(aws.String("gp3")), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
|
|
||||||
|
|
||||||
cluster.VolumeResizer = resizer
|
|
||||||
cluster.syncVolumes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestManualGp2Gp3Support(t *testing.T) {
|
|
||||||
client, _ := newFakeK8sPVCclient()
|
|
||||||
clusterName := "acid-test-cluster"
|
|
||||||
namespace := "default"
|
|
||||||
|
|
||||||
// new cluster with pvc storage resize mode and configured labels
|
|
||||||
var cluster = New(
|
|
||||||
Config{
|
|
||||||
OpConfig: config.Config{
|
|
||||||
Resources: config.Resources{
|
|
||||||
ClusterLabels: map[string]string{"application": "spilo"},
|
|
||||||
ClusterNameLabel: "cluster-name",
|
|
||||||
},
|
|
||||||
StorageResizeMode: "mixed",
|
|
||||||
EnableEBSGp3Migration: false,
|
|
||||||
EnableEBSGp3MigrationMaxSize: 1000,
|
|
||||||
},
|
|
||||||
}, client, acidv1.Postgresql{}, logger, eventRecorder)
|
|
||||||
|
|
||||||
cluster.Spec.Volume.Size = "150Gi"
|
|
||||||
cluster.Spec.Volume.Iops = aws.Int64(6000)
|
|
||||||
cluster.Spec.Volume.Throughput = aws.Int64(275)
|
|
||||||
|
|
||||||
// set metadata, so that labels will get correct values
|
// set metadata, so that labels will get correct values
|
||||||
cluster.Name = clusterName
|
cluster.Name = clusterName
|
||||||
|
|
@ -402,14 +279,14 @@ func TestManualGp2Gp3Support(t *testing.T) {
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
// expect only gp2 volume to be modified
|
// expect only gp2 volume to be modified
|
||||||
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Eq(aws.String("gp3")), gomock.Nil(), gomock.Eq(aws.Int64(6000)), gomock.Eq(aws.Int64(275))).Return(nil)
|
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Eq(aws.String("gp3")), gomock.Nil(), gomock.Eq(aws.Int32(6000)), gomock.Eq(aws.Int32(275))).Return(nil)
|
||||||
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-2"), gomock.Eq(aws.String("gp3")), gomock.Nil(), gomock.Eq(aws.Int64(6000)), gomock.Eq(aws.Int64(275))).Return(nil)
|
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-2"), gomock.Eq(aws.String("gp3")), gomock.Nil(), gomock.Eq(aws.Int32(6000)), gomock.Eq(aws.Int32(275))).Return(nil)
|
||||||
|
|
||||||
cluster.VolumeResizer = resizer
|
cluster.VolumeResizer = resizer
|
||||||
cluster.syncVolumes()
|
cluster.syncVolumes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDontTouchType(t *testing.T) {
|
func TestNoVolumeTypeChange(t *testing.T) {
|
||||||
client, _ := newFakeK8sPVCclient()
|
client, _ := newFakeK8sPVCclient()
|
||||||
clusterName := "acid-test-cluster"
|
clusterName := "acid-test-cluster"
|
||||||
namespace := "default"
|
namespace := "default"
|
||||||
|
|
@ -422,9 +299,7 @@ func TestDontTouchType(t *testing.T) {
|
||||||
ClusterLabels: map[string]string{"application": "spilo"},
|
ClusterLabels: map[string]string{"application": "spilo"},
|
||||||
ClusterNameLabel: "cluster-name",
|
ClusterNameLabel: "cluster-name",
|
||||||
},
|
},
|
||||||
StorageResizeMode: "mixed",
|
StorageResizeMode: "mixed",
|
||||||
EnableEBSGp3Migration: false,
|
|
||||||
EnableEBSGp3MigrationMaxSize: 1000,
|
|
||||||
},
|
},
|
||||||
}, client, acidv1.Postgresql{}, logger, eventRecorder)
|
}, client, acidv1.Postgresql{}, logger, eventRecorder)
|
||||||
|
|
||||||
|
|
@ -467,8 +342,8 @@ func TestDontTouchType(t *testing.T) {
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
// expect only gp2 volume to be modified
|
// expect only gp2 volume to be modified
|
||||||
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Nil(), gomock.Eq(aws.Int64(177)), gomock.Nil(), gomock.Nil()).Return(nil)
|
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Nil(), gomock.Eq(aws.Int32(177)), gomock.Nil(), gomock.Nil()).Return(nil)
|
||||||
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-2"), gomock.Nil(), gomock.Eq(aws.Int64(177)), gomock.Nil(), gomock.Nil()).Return(nil)
|
resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-2"), gomock.Nil(), gomock.Eq(aws.Int32(177)), gomock.Nil(), gomock.Nil()).Return(nil)
|
||||||
|
|
||||||
cluster.VolumeResizer = resizer
|
cluster.VolumeResizer = resizer
|
||||||
cluster.syncVolumes()
|
cluster.syncVolumes()
|
||||||
|
|
|
||||||
|
|
@ -181,8 +181,6 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||||
result.WALAZStorageAccount = fromCRD.AWSGCP.WALAZStorageAccount
|
result.WALAZStorageAccount = fromCRD.AWSGCP.WALAZStorageAccount
|
||||||
result.AdditionalSecretMount = fromCRD.AWSGCP.AdditionalSecretMount
|
result.AdditionalSecretMount = fromCRD.AWSGCP.AdditionalSecretMount
|
||||||
result.AdditionalSecretMountPath = fromCRD.AWSGCP.AdditionalSecretMountPath
|
result.AdditionalSecretMountPath = fromCRD.AWSGCP.AdditionalSecretMountPath
|
||||||
result.EnableEBSGp3Migration = fromCRD.AWSGCP.EnableEBSGp3Migration
|
|
||||||
result.EnableEBSGp3MigrationMaxSize = util.CoalesceInt64(fromCRD.AWSGCP.EnableEBSGp3MigrationMaxSize, 1000)
|
|
||||||
|
|
||||||
// logical backup config
|
// logical backup config
|
||||||
result.LogicalBackupSchedule = util.Coalesce(fromCRD.LogicalBackup.Schedule, "30 00 * * *")
|
result.LogicalBackupSchedule = util.Coalesce(fromCRD.LogicalBackup.Schedule, "30 00 * * *")
|
||||||
|
|
|
||||||
|
|
@ -200,8 +200,6 @@ type Config struct {
|
||||||
WALAZStorageAccount string `name:"wal_az_storage_account"`
|
WALAZStorageAccount string `name:"wal_az_storage_account"`
|
||||||
AdditionalSecretMount string `name:"additional_secret_mount"`
|
AdditionalSecretMount string `name:"additional_secret_mount"`
|
||||||
AdditionalSecretMountPath string `name:"additional_secret_mount_path"`
|
AdditionalSecretMountPath string `name:"additional_secret_mount_path"`
|
||||||
EnableEBSGp3Migration bool `name:"enable_ebs_gp3_migration" default:"false"`
|
|
||||||
EnableEBSGp3MigrationMaxSize int64 `name:"enable_ebs_gp3_migration_max_size" default:"1000"`
|
|
||||||
DebugLogging bool `name:"debug_logging" default:"true"`
|
DebugLogging bool `name:"debug_logging" default:"true"`
|
||||||
EnableDBAccess bool `name:"enable_database_access" default:"true"`
|
EnableDBAccess bool `name:"enable_database_access" default:"true"`
|
||||||
EnableTeamsAPI bool `name:"enable_teams_api" default:"true"`
|
EnableTeamsAPI bool `name:"enable_teams_api" default:"true"`
|
||||||
|
|
|
||||||
|
|
@ -89,21 +89,21 @@ func (r *EBSVolumeResizer) DescribeVolumes(volumeIds []string) ([]VolumeProperti
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range volumeOutput.Volumes {
|
for _, v := range volumeOutput.Volumes {
|
||||||
switch v.VolumeType {
|
vp := VolumeProperties{VolumeID: *v.VolumeId, Size: int32(*v.Size), VolumeType: string(v.VolumeType)}
|
||||||
case "gp3":
|
if v.Iops != nil {
|
||||||
p = append(p, VolumeProperties{VolumeID: *v.VolumeId, Size: int64(*v.Size), VolumeType: string(v.VolumeType), Iops: int64(*v.Iops), Throughput: int64(*v.Throughput)})
|
vp.Iops = int32(*v.Iops)
|
||||||
case "gp2":
|
|
||||||
p = append(p, VolumeProperties{VolumeID: *v.VolumeId, Size: int64(*v.Size), VolumeType: string(v.VolumeType)})
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("discovered unexpected volume type %s %s", *v.VolumeId, v.VolumeType)
|
|
||||||
}
|
}
|
||||||
|
if v.Throughput != nil {
|
||||||
|
vp.Throughput = int32(*v.Throughput)
|
||||||
|
}
|
||||||
|
p = append(p, vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResizeVolume actually calls AWS API to resize the EBS volume if necessary.
|
// ResizeVolume actually calls AWS API to resize the EBS volume if necessary.
|
||||||
func (r *EBSVolumeResizer) ResizeVolume(volumeID string, newSize int64) error {
|
func (r *EBSVolumeResizer) ResizeVolume(volumeID string, newSize int32) error {
|
||||||
/* first check if the volume is already of a requested size */
|
/* first check if the volume is already of a requested size */
|
||||||
volumeOutput, err := r.connection.DescribeVolumes(context.TODO(), &ec2.DescribeVolumesInput{VolumeIds: []string{volumeID}})
|
volumeOutput, err := r.connection.DescribeVolumes(context.TODO(), &ec2.DescribeVolumesInput{VolumeIds: []string{volumeID}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -113,12 +113,11 @@ func (r *EBSVolumeResizer) ResizeVolume(volumeID string, newSize int64) error {
|
||||||
if *vol.VolumeId != volumeID {
|
if *vol.VolumeId != volumeID {
|
||||||
return fmt.Errorf("describe volume %q returned information about a non-matching volume %q", volumeID, *vol.VolumeId)
|
return fmt.Errorf("describe volume %q returned information about a non-matching volume %q", volumeID, *vol.VolumeId)
|
||||||
}
|
}
|
||||||
sizeInt32 := int32(newSize)
|
if *vol.Size == newSize {
|
||||||
if *vol.Size == sizeInt32 {
|
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
input := ec2.ModifyVolumeInput{Size: &sizeInt32, VolumeId: &volumeID}
|
input := ec2.ModifyVolumeInput{Size: &newSize, VolumeId: &volumeID}
|
||||||
output, err := r.connection.ModifyVolume(context.TODO(), &input)
|
output, err := r.connection.ModifyVolume(context.TODO(), &input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not modify persistent volume: %v", err)
|
return fmt.Errorf("could not modify persistent volume: %v", err)
|
||||||
|
|
@ -154,28 +153,16 @@ func (r *EBSVolumeResizer) ResizeVolume(volumeID string, newSize int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModifyVolume Modify EBS volume
|
// ModifyVolume Modify EBS volume
|
||||||
func (r *EBSVolumeResizer) ModifyVolume(volumeID string, newType *string, newSize *int64, iops *int64, throughput *int64) error {
|
func (r *EBSVolumeResizer) ModifyVolume(volumeID string, newType *string, newSize *int32, iops *int32, throughput *int32) error {
|
||||||
var sizeInt32 *int32
|
input := ec2.ModifyVolumeInput{VolumeId: &volumeID}
|
||||||
var iopsInt32 *int32
|
|
||||||
var throughputInt32 *int32
|
|
||||||
|
|
||||||
input := ec2.ModifyVolumeInput{
|
|
||||||
VolumeId: &volumeID,
|
|
||||||
}
|
|
||||||
if newSize != nil {
|
if newSize != nil {
|
||||||
s := int32(*newSize)
|
input.Size = newSize
|
||||||
sizeInt32 = &s
|
|
||||||
input.Size = sizeInt32
|
|
||||||
}
|
}
|
||||||
if iops != nil {
|
if iops != nil {
|
||||||
i := int32(*iops)
|
input.Iops = iops
|
||||||
iopsInt32 = &i
|
|
||||||
input.Iops = iopsInt32
|
|
||||||
}
|
}
|
||||||
if throughput != nil {
|
if throughput != nil {
|
||||||
t := int32(*throughput)
|
input.Throughput = throughput
|
||||||
throughputInt32 = &t
|
|
||||||
input.Throughput = throughputInt32
|
|
||||||
}
|
}
|
||||||
if newType != nil {
|
if newType != nil {
|
||||||
input.VolumeType = types.VolumeType(*newType)
|
input.VolumeType = types.VolumeType(*newType)
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ import v1 "k8s.io/api/core/v1"
|
||||||
type VolumeProperties struct {
|
type VolumeProperties struct {
|
||||||
VolumeID string
|
VolumeID string
|
||||||
VolumeType string
|
VolumeType string
|
||||||
Size int64
|
Size int32
|
||||||
Iops int64
|
Iops int32
|
||||||
Throughput int64
|
Throughput int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// VolumeResizer defines the set of methods used to implememnt provider-specific resizing of persistent volumes.
|
// VolumeResizer defines the set of methods used to implememnt provider-specific resizing of persistent volumes.
|
||||||
|
|
@ -20,8 +20,8 @@ type VolumeResizer interface {
|
||||||
VolumeBelongsToProvider(pv *v1.PersistentVolume) bool
|
VolumeBelongsToProvider(pv *v1.PersistentVolume) bool
|
||||||
GetProviderVolumeID(pv *v1.PersistentVolume) (string, error)
|
GetProviderVolumeID(pv *v1.PersistentVolume) (string, error)
|
||||||
ExtractVolumeID(volumeID string) (string, error)
|
ExtractVolumeID(volumeID string) (string, error)
|
||||||
ResizeVolume(providerVolumeID string, newSize int64) error
|
ResizeVolume(providerVolumeID string, newSize int32) error
|
||||||
ModifyVolume(providerVolumeID string, newType *string, newSize *int64, iops *int64, throughput *int64) error
|
ModifyVolume(providerVolumeID string, newType *string, newSize *int32, iops *int32, throughput *int32) error
|
||||||
DisconnectFromProvider() error
|
DisconnectFromProvider() error
|
||||||
DescribeVolumes(providerVolumesID []string) ([]VolumeProperties, error)
|
DescribeVolumes(providerVolumesID []string) ([]VolumeProperties, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,8 @@ spec:
|
||||||
"cost_memory": 0.014375,
|
"cost_memory": 0.014375,
|
||||||
"free_iops": 3000,
|
"free_iops": 3000,
|
||||||
"free_throughput": 125,
|
"free_throughput": 125,
|
||||||
"limit_iops": 16000,
|
"limit_iops": 80000,
|
||||||
"limit_throughput": 1000,
|
"limit_throughput": 2000,
|
||||||
"postgresql_versions": [
|
"postgresql_versions": [
|
||||||
"18",
|
"18",
|
||||||
"17",
|
"17",
|
||||||
|
|
|
||||||
|
|
@ -86,9 +86,9 @@ COST_ELB = float(getenv('COST_ELB', 0.03)) # per hour
|
||||||
|
|
||||||
# maximum and limitation of IOPS and throughput
|
# maximum and limitation of IOPS and throughput
|
||||||
FREE_IOPS = float(getenv('FREE_IOPS', 3000))
|
FREE_IOPS = float(getenv('FREE_IOPS', 3000))
|
||||||
LIMIT_IOPS = float(getenv('LIMIT_IOPS', 16000))
|
LIMIT_IOPS = float(getenv('LIMIT_IOPS', 80000))
|
||||||
FREE_THROUGHPUT = float(getenv('FREE_THROUGHPUT', 125))
|
FREE_THROUGHPUT = float(getenv('FREE_THROUGHPUT', 125))
|
||||||
LIMIT_THROUGHPUT = float(getenv('LIMIT_THROUGHPUT', 1000))
|
LIMIT_THROUGHPUT = float(getenv('LIMIT_THROUGHPUT', 2000))
|
||||||
# get the default value of core and memory
|
# get the default value of core and memory
|
||||||
DEFAULT_MEMORY = getenv('DEFAULT_MEMORY', '300Mi')
|
DEFAULT_MEMORY = getenv('DEFAULT_MEMORY', '300Mi')
|
||||||
DEFAULT_MEMORY_LIMIT = getenv('DEFAULT_MEMORY_LIMIT', '300Mi')
|
DEFAULT_MEMORY_LIMIT = getenv('DEFAULT_MEMORY_LIMIT', '300Mi')
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ default_operator_ui_config='{
|
||||||
"cost_memory": 0.014375,
|
"cost_memory": 0.014375,
|
||||||
"free_iops": 3000,
|
"free_iops": 3000,
|
||||||
"free_throughput": 125,
|
"free_throughput": 125,
|
||||||
"limit_iops": 16000,
|
"limit_iops": 80000,
|
||||||
"limit_throughput": 1000,
|
"limit_throughput": 2000,
|
||||||
"postgresql_versions": [
|
"postgresql_versions": [
|
||||||
"18",
|
"18",
|
||||||
"17",
|
"17",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue