Merge branch 'master' into check-cluster-UID

This commit is contained in:
Felix Kunde 2026-06-29 11:56:49 +02:00 committed by GitHub
commit 33d89c1a7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 651 additions and 353 deletions

View File

@ -75,7 +75,10 @@ $(GENERATED_CRDS): $(GENERATED)
@mv manifests/acid.zalan.do_operatorconfigurations.yaml manifests/operatorconfiguration.crd.yaml
@mv manifests/acid.zalan.do_postgresteams.yaml manifests/postgresteam.crd.yaml
@cp manifests/postgresql.crd.yaml pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml
@cp manifests/postgresql.crd.yaml charts/postgres-operator/crds/postgresqls.yaml
@cp manifests/operatorconfiguration.crd.yaml pkg/apis/acid.zalan.do/v1/operatorconfiguration.crd.yaml
@cp manifests/operatorconfiguration.crd.yaml charts/postgres-operator/crds/operatorconfigurations.yaml
@cp manifests/postgresteam.crd.yaml charts/postgres-operator/crds/postgresteams.yaml
local: ${SOURCES} $(GENERATED_CRDS)
CGO_ENABLED=${CGO_ENABLED} go build -o build/${BINARY} $(LOCAL_BUILD_FLAGS) -ldflags "$(LDFLAGS)" $(SOURCES)

View File

@ -1,9 +1,12 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: operatorconfigurations.acid.zalan.do
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
labels:
app.kubernetes.io/name: postgres-operator
name: operatorconfigurations.acid.zalan.do
spec:
group: acid.zalan.do
names:
@ -444,8 +447,7 @@ spec:
default: 20m
description: timeout for successful migration of master pods from
unschedulable node
format: int64
type: integer
type: string
node_readiness_label:
additionalProperties:
type: string
@ -518,8 +520,7 @@ spec:
default: 5m
description: Postgres pods are terminated forcefully after this
timeout
format: int64
type: integer
type: string
secret_name_template:
default: '{username}.{cluster}.credentials.{tprkind}.{tprgroup}'
description: |-
@ -703,6 +704,10 @@ spec:
type: integer
type: object
maintenance_windows:
items:
pattern: ^\ *((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\d):([0-5]?\d)|(2[0-3]|[01]?\d):([0-5]?\d))-((2[0-3]|[01]?\d):([0-5]?\d)|(2[0-3]|[01]?\d):([0-5]?\d))\
*$
type: string
type: array
major_version_upgrade:
description: MajorVersionUpgradeConfiguration defines how to execute
@ -776,13 +781,11 @@ spec:
repair_period:
default: 5m
description: period between consecutive repair requests
format: int64
type: integer
type: string
resync_period:
default: 30m
description: period between consecutive sync requests
format: int64
type: integer
type: string
scalyr:
description: ScalyrConfiguration defines the configuration for ScalyrAPI
properties:
@ -848,7 +851,9 @@ spec:
type: string
type: array
protected_role_names:
default: '["admin", "cron_admin"]'
default:
- admin
- cron_admin
items:
type: string
type: array
@ -876,48 +881,40 @@ spec:
default: 1s
description: interval between consecutive attempts of operator
calling the Patroni API
format: int64
type: integer
type: string
patroni_api_check_timeout:
default: 5s
description: timeout when waiting for successful response from
Patroni API
format: int64
type: integer
type: string
pod_deletion_wait_timeout:
default: 10m
description: timeout when waiting for the Postgres pods to be
deleted
format: int64
type: integer
type: string
pod_label_wait_timeout:
default: 10m
description: timeout when waiting for pod role and cluster labels
format: int64
type: integer
type: string
ready_wait_interval:
default: 4s
description: interval between consecutive attempts waiting for
postgresql CRD to be created
format: int64
type: integer
type: string
ready_wait_timeout:
default: 30s
description: timeout for the complete postgres CRD creation
format: int64
type: integer
type: string
resource_check_interval:
default: 3s
description: interval to wait between consecutive attempts to
check for some K8s resources
format: int64
type: integer
type: string
resource_check_timeout:
default: 10m
description: timeout when waiting for the presence of a certain
K8s resource
format: int64
type: integer
type: string
type: object
users:
description: PostgresUsersConfiguration defines the system users of

View File

@ -1,9 +1,12 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: postgresqls.acid.zalan.do
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
labels:
app.kubernetes.io/name: postgres-operator
name: postgresqls.acid.zalan.do
spec:
group: acid.zalan.do
names:
@ -301,7 +304,9 @@ spec:
a Container.
properties:
name:
description: Name of the environment variable. Must be a C_IDENTIFIER.
description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string
value:
description: |-
@ -359,6 +364,43 @@ spec:
- fieldPath
type: object
x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing
the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: |-
Selects a resource of the container: only resources limits and requests
@ -455,8 +497,9 @@ spec:
in a Container.
properties:
name:
description: Name of the environment variable. Must be
a C_IDENTIFIER.
description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string
value:
description: |-
@ -514,6 +557,43 @@ spec:
- fieldPath
type: object
x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing
the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: |-
Selects a resource of the container: only resources limits and requests
@ -574,14 +654,14 @@ spec:
envFrom:
description: |-
List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
will be reported as an event when the container is starting. When a key exists in multiple
The keys defined within a source may consist of any printable ASCII characters except '='.
When a key exists in multiple
sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence.
Cannot be updated.
items:
description: EnvFromSource represents the source of a set
of ConfigMaps
of ConfigMaps or Secrets
properties:
configMapRef:
description: The ConfigMap to select from
@ -602,8 +682,9 @@ spec:
type: object
x-kubernetes-map-type: atomic
prefix:
description: An optional identifier to prepend to each
key in the ConfigMap. Must be a C_IDENTIFIER.
description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string
secretRef:
description: The Secret to select from
@ -866,6 +947,12 @@ spec:
- port
type: object
type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object
livenessProbe:
description: |-
@ -1236,7 +1323,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents resource resize
policy for the container.
@ -1268,7 +1357,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container.
This is an alpha field and requires enabling the
This field depends on the
DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers.
@ -1322,10 +1411,10 @@ spec:
restartPolicy:
description: |-
RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always".
For non-init containers or when this field is not specified,
This overrides the pod-level restart policy. When this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect:
Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always"
@ -1337,6 +1426,59 @@ spec:
init container is started, or after any startupProbe has successfully
completed.
type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container
exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container
exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext:
description: |-
SecurityContext defines the security options the container should be run with.
@ -1412,7 +1554,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@ -1877,8 +2018,9 @@ spec:
in a Container.
properties:
name:
description: Name of the environment variable. Must be
a C_IDENTIFIER.
description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string
value:
description: |-
@ -1936,6 +2078,43 @@ spec:
- fieldPath
type: object
x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing
the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: |-
Selects a resource of the container: only resources limits and requests
@ -1996,14 +2175,14 @@ spec:
envFrom:
description: |-
List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
will be reported as an event when the container is starting. When a key exists in multiple
The keys defined within a source may consist of any printable ASCII characters except '='.
When a key exists in multiple
sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence.
Cannot be updated.
items:
description: EnvFromSource represents the source of a set
of ConfigMaps
of ConfigMaps or Secrets
properties:
configMapRef:
description: The ConfigMap to select from
@ -2024,8 +2203,9 @@ spec:
type: object
x-kubernetes-map-type: atomic
prefix:
description: An optional identifier to prepend to each
key in the ConfigMap. Must be a C_IDENTIFIER.
description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string
secretRef:
description: The Secret to select from
@ -2288,6 +2468,12 @@ spec:
- port
type: object
type: object
stopSignal:
description: |-
StopSignal defines which signal will be sent to a container when it is being stopped.
If not specified, the default is defined by the container runtime in use.
StopSignal can only be set for Pods with a non-empty .spec.os.name
type: string
type: object
livenessProbe:
description: |-
@ -2658,7 +2844,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents resource resize
policy for the container.
@ -2690,7 +2878,7 @@ spec:
Claims lists the names of resources, defined in spec.resourceClaims,
that are used by this container.
This is an alpha field and requires enabling the
This field depends on the
DynamicResourceAllocation feature gate.
This field is immutable. It can only be set for containers.
@ -2744,10 +2932,10 @@ spec:
restartPolicy:
description: |-
RestartPolicy defines the restart behavior of individual containers in a pod.
This field may only be set for init containers, and the only allowed value is "Always".
For non-init containers or when this field is not specified,
This overrides the pod-level restart policy. When this field is not specified,
the restart behavior is defined by the Pod's restart policy and the container type.
Setting the RestartPolicy as "Always" for the init container will have the following effect:
Additionally, setting the RestartPolicy as "Always" for the init container will
have the following effect:
this init container will be continually restarted on
exit until all regular containers have terminated. Once all regular
containers have completed, all init containers with restartPolicy "Always"
@ -2759,6 +2947,59 @@ spec:
init container is started, or after any startupProbe has successfully
completed.
type: string
restartPolicyRules:
description: |-
Represents a list of rules to be checked to determine if the
container should be restarted on exit. The rules are evaluated in
order. Once a rule matches a container exit condition, the remaining
rules are ignored. If no rule matches the container exit condition,
the Container-level restart policy determines the whether the container
is restarted or not. Constraints on the rules:
- At most 20 rules are allowed.
- Rules can have the same action.
- Identical rules are not forbidden in validations.
When rules are specified, container MUST set RestartPolicy explicitly
even it if matches the Pod's RestartPolicy.
items:
description: ContainerRestartRule describes how a container
exit is handled.
properties:
action:
description: |-
Specifies the action taken on a container exit if the requirements
are satisfied. The only possible value is "Restart" to restart the
container.
type: string
exitCodes:
description: Represents the exit codes to check on container
exits.
properties:
operator:
description: |-
Represents the relationship between the container exit code(s) and the
specified values. Possible values are:
- In: the requirement is satisfied if the container exit code is in the
set of specified values.
- NotIn: the requirement is satisfied if the container exit code is
not in the set of specified values.
type: string
values:
description: |-
Specifies the set of values to check for container exit codes.
At most 255 elements are allowed.
items:
format: int32
type: integer
type: array
x-kubernetes-list-type: set
required:
- operator
type: object
required:
- action
type: object
type: array
x-kubernetes-list-type: atomic
securityContext:
description: |-
SecurityContext defines the security options the container should be run with.
@ -2834,7 +3075,6 @@ spec:
procMount denotes the type of proc mount to use for the containers.
The default value is Default which uses the container runtime defaults for
readonly paths and masked paths.
This requires the ProcMountType feature flag to be enabled.
Note that this field cannot be set when spec.os.name is windows.
type: string
readOnlyRootFilesystem:
@ -3848,8 +4088,9 @@ spec:
in a Container.
properties:
name:
description: Name of the environment variable. Must be
a C_IDENTIFIER.
description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string
value:
description: |-
@ -3907,6 +4148,43 @@ spec:
- fieldPath
type: object
x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing
the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: |-
Selects a resource of the container: only resources limits and requests
@ -4213,9 +4491,10 @@ spec:
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
type: string
tolerationSeconds:
description: |-
@ -4354,7 +4633,6 @@ spec:
- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
If this value is nil, the behavior is equivalent to the Honor policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string
nodeTaintsPolicy:
description: |-
@ -4365,7 +4643,6 @@ spec:
- Ignore: node taints are ignored. All nodes are included.
If this value is nil, the behavior is equivalent to the Ignore policy.
This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.
type: string
topologyKey:
description: |-

View File

@ -1,70 +1,84 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: postgresteams.acid.zalan.do
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
labels:
app.kubernetes.io/name: postgres-operator
name: postgresteams.acid.zalan.do
spec:
group: acid.zalan.do
names:
categories:
- all
kind: PostgresTeam
listKind: PostgresTeamList
plural: postgresteams
singular: postgresteam
shortNames:
- pgteam
categories:
- all
singular: postgresteam
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
description: PostgresTeam defines Custom Resource Definition Object for team
management.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: PostgresTeamSpec defines the specification for the PostgresTeam
TPR.
properties:
additionalMembers:
additionalProperties:
description: List of users who will also be added to the Postgres
cluster.
items:
type: string
type: array
description: Map for teamId and associated additional users
type: object
additionalSuperuserTeams:
additionalProperties:
description: List of teams to become Postgres superusers
items:
type: string
type: array
description: Map for teamId and associated additional superuser teams
type: object
additionalTeams:
additionalProperties:
description: List of teams whose members will also be added to the
Postgres cluster.
items:
type: string
type: array
description: Map for teamId and associated additional teams
type: object
type: object
required:
- metadata
- spec
type: object
served: true
storage: true
subresources:
status: {}
schema:
openAPIV3Schema:
type: object
required:
- kind
- apiVersion
- spec
properties:
kind:
type: string
enum:
- PostgresTeam
apiVersion:
type: string
enum:
- acid.zalan.do/v1
spec:
type: object
properties:
additionalSuperuserTeams:
type: object
description: "Map for teamId and associated additional superuser teams"
additionalProperties:
type: array
nullable: true
description: "List of teams to become Postgres superusers"
items:
type: string
additionalTeams:
type: object
description: "Map for teamId and associated additional teams"
additionalProperties:
type: array
nullable: true
description: "List of teams whose members will also be added to the Postgres cluster"
items:
type: string
additionalMembers:
type: object
description: "Map for teamId and associated additional users"
additionalProperties:
type: array
nullable: true
description: "List of users who will also be added to the Postgres cluster"
items:
type: string

View File

@ -518,7 +518,6 @@ podPriorityClassName:
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 100m

View File

@ -27,20 +27,11 @@ git clone https://github.com/zalando/postgres-operator.git
## Building the operator
We use [Go Modules](https://github.com/golang/go/wiki/Modules) for handling
dependencies. When using Go below v1.13 you need to explicitly enable Go modules
by setting the `GO111MODULE` environment variable to `on`. The make targets do
this for you, so simply run
We use [Go Modules](https://github.com/golang/go/wiki/Modules) for handling dependencies.
Run `go mod vendor && go mod tidy` to install them.
```bash
make
```
Build the operator with the `make docker` command. You may define the TAG
variable to assign an explicit tag to your Docker image and the IMAGE to set
the image name. By default, the tag is computed with
`git describe --tags --always --dirty` and the image is
`ghcr.io/zalando/postgres-operator`
Build the operator with the `make docker` command. You may define the TAG variable to assign an explicit tag to your Docker image and the IMAGE to set the image name. By default, the tag is computed with
`git describe --tags --always --dirty` and the image is `ghcr.io/zalando/postgres-operator`. On macos search and replace `sed -i` commands with `sed -i ''` for the make commands to work.
```bash
export TAG=$(git describe --tags --always --dirty)
@ -296,8 +287,7 @@ Please run flake8 [before submitting a PR](http://flake8.pycqa.org/en/latest/use
In the case you want to add functionality to the operator that shall be
controlled via the operator configuration there are a few places that need to
be updated. As explained [here](reference/operator_parameters.md), it's possible
to configure the operator either with a ConfigMap or CRD, but currently we aim
to synchronize parameters everywhere.
to configure the operator either with a ConfigMap or CRD.
When choosing a parameter name for a new option in a Postgres cluster manifest,
keep in mind the naming conventions there. We use `camelCase` for manifest
@ -320,32 +310,28 @@ manifest files:
Postgres manifest parameters are defined in the [api package](https://github.com/zalando/postgres-operator/blob/master/pkg/apis/acid.zalan.do/v1/postgresql_type.go).
The operator behavior has to be implemented at least in [k8sres.go](https://github.com/zalando/postgres-operator/blob/master/pkg/cluster/k8sres.go).
Validation of CRD parameters is controlled in [crds.go](https://github.com/zalando/postgres-operator/blob/master/pkg/apis/acid.zalan.do/v1/crds.go).
Please, reflect your changes in tests, for example in:
* [config_test.go](https://github.com/zalando/postgres-operator/blob/master/pkg/util/config/config_test.go)
* [k8sres_test.go](https://github.com/zalando/postgres-operator/blob/master/pkg/cluster/k8sres_test.go)
* [util_test.go](https://github.com/zalando/postgres-operator/blob/master/pkg/apis/acid.zalan.do/v1/util_test.go)
### Updating manifest files
### Generating the CRDs
For the CRD-based configuration, please update the following files:
* the default [OperatorConfiguration](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresql-operator-default-configuration.yaml)
* the CRD's [validation](https://github.com/zalando/postgres-operator/blob/master/manifests/operatorconfiguration.crd.yaml)
* the CRD's validation in the [Helm chart](https://github.com/zalando/postgres-operator/blob/master/charts/postgres-operator/crds/operatorconfigurations.yaml)
Add new options also to the Helm chart's [values file](https://github.com/zalando/postgres-operator/blob/master/charts/postgres-operator/values.yaml) file.
It follows the OperatorConfiguration CRD layout. Nested values will be flattened for the ConfigMap.
Last but no least, update the [ConfigMap](https://github.com/zalando/postgres-operator/blob/master/manifests/configmap.yaml) manifest example as well.
The CRDs can be automatically generated from the go structs. Use the correct kubebuilder annotations for defining the validation, constraints or default values etc.. Run `make` to update the CRDs which are stored in three locations:
- In the Go api package
- The example manifests folder
- The helm chart folder
### Updating documentation
Finally, add a section for each new configuration option and/or cluster manifest
Config changes need to be reflected in the Helm chart's [values file](https://github.com/zalando/postgres-operator/blob/master/charts/postgres-operator/values.yaml), too. It follows the OperatorConfiguration CRD layout. Nested values will be flattened for the ConfigMap.
Add a section for each new configuration option and/or cluster manifest
parameter in the reference documents:
* [config reference](reference/operator_parameters.md)
* [manifest reference](reference/cluster_manifest.md)
It also helps users to explain new features with examples in the
[administrator docs](administrator.md).
It can also help other K8s admins to explain new features with examples in the
[administrator docs](administrator.md) and also update the [OperatorConfiguration CRD](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresql-operator-default-configuration.yaml) and [ConfigMap](https://github.com/zalando/postgres-operator/blob/master/manifests/configmap.yaml) manifest examples.

View File

@ -4,6 +4,8 @@ kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
labels:
app.kubernetes.io/name: postgres-operator
name: operatorconfigurations.acid.zalan.do
spec:
group: acid.zalan.do
@ -445,8 +447,7 @@ spec:
default: 20m
description: timeout for successful migration of master pods from
unschedulable node
format: int64
type: integer
type: string
node_readiness_label:
additionalProperties:
type: string
@ -519,8 +520,7 @@ spec:
default: 5m
description: Postgres pods are terminated forcefully after this
timeout
format: int64
type: integer
type: string
secret_name_template:
default: '{username}.{cluster}.credentials.{tprkind}.{tprgroup}'
description: |-
@ -704,6 +704,10 @@ spec:
type: integer
type: object
maintenance_windows:
items:
pattern: ^\ *((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\d):([0-5]?\d)|(2[0-3]|[01]?\d):([0-5]?\d))-((2[0-3]|[01]?\d):([0-5]?\d)|(2[0-3]|[01]?\d):([0-5]?\d))\
*$
type: string
type: array
major_version_upgrade:
description: MajorVersionUpgradeConfiguration defines how to execute
@ -777,13 +781,11 @@ spec:
repair_period:
default: 5m
description: period between consecutive repair requests
format: int64
type: integer
type: string
resync_period:
default: 30m
description: period between consecutive sync requests
format: int64
type: integer
type: string
scalyr:
description: ScalyrConfiguration defines the configuration for ScalyrAPI
properties:
@ -849,7 +851,9 @@ spec:
type: string
type: array
protected_role_names:
default: '["admin", "cron_admin"]'
default:
- admin
- cron_admin
items:
type: string
type: array
@ -877,48 +881,40 @@ spec:
default: 1s
description: interval between consecutive attempts of operator
calling the Patroni API
format: int64
type: integer
type: string
patroni_api_check_timeout:
default: 5s
description: timeout when waiting for successful response from
Patroni API
format: int64
type: integer
type: string
pod_deletion_wait_timeout:
default: 10m
description: timeout when waiting for the Postgres pods to be
deleted
format: int64
type: integer
type: string
pod_label_wait_timeout:
default: 10m
description: timeout when waiting for pod role and cluster labels
format: int64
type: integer
type: string
ready_wait_interval:
default: 4s
description: interval between consecutive attempts waiting for
postgresql CRD to be created
format: int64
type: integer
type: string
ready_wait_timeout:
default: 30s
description: timeout for the complete postgres CRD creation
format: int64
type: integer
type: string
resource_check_interval:
default: 3s
description: interval to wait between consecutive attempts to
check for some K8s resources
format: int64
type: integer
type: string
resource_check_timeout:
default: 10m
description: timeout when waiting for the presence of a certain
K8s resource
format: int64
type: integer
type: string
type: object
users:
description: PostgresUsersConfiguration defines the system users of

View File

@ -4,6 +4,8 @@ kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
labels:
app.kubernetes.io/name: postgres-operator
name: postgresqls.acid.zalan.do
spec:
group: acid.zalan.do

View File

@ -4,6 +4,8 @@ kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
labels:
app.kubernetes.io/name: postgres-operator
name: postgresteams.acid.zalan.do
spec:
group: acid.zalan.do

View File

@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"strings"
"time"
)
type postgresqlCopy Postgresql
@ -120,29 +119,3 @@ func (p *Postgresql) UnmarshalJSON(data []byte) error {
return nil
}
// UnmarshalJSON convert to Duration from byte slice of json
func (d *Duration) UnmarshalJSON(b []byte) error {
var (
v interface{}
err error
)
if err = json.Unmarshal(b, &v); err != nil {
return err
}
switch val := v.(type) {
case string:
t, err := time.ParseDuration(val)
if err != nil {
return err
}
*d = Duration(t)
return nil
case float64:
t := time.Duration(val)
*d = Duration(t)
return nil
default:
return fmt.Errorf("could not recognize type %T as a valid type to unmarshal to Duration", val)
}
}

View File

@ -5,8 +5,6 @@ package v1
import (
"github.com/zalando/postgres-operator/pkg/util/config"
"time"
"github.com/zalando/postgres-operator/pkg/spec"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -24,6 +22,7 @@ import (
// +kubebuilder:printcolumn:name="Min-Instances",type=integer,JSONPath=`.configuration.min_instances`,description="Minimum number of instances per Postgres cluster"
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`,description="Age of the OperatorConfiguration resource"
// +kubebuilder:subresource:status
// +kubebuilder:metadata:labels=app.kubernetes.io/name=postgres-operator
type OperatorConfiguration struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`
@ -77,7 +76,7 @@ type KubernetesMetaConfiguration struct {
PodServiceAccountRoleBindingDefinition string `json:"pod_service_account_role_binding_definition,omitempty"`
// +kubebuilder:default="5m"
// Postgres pods are terminated forcefully after this timeout
PodTerminateGracePeriod Duration `json:"pod_terminate_grace_period,omitempty"`
PodTerminateGracePeriod *metav1.Duration `json:"pod_terminate_grace_period,omitempty"`
// +optional
LivenessProbe *v1.Probe `json:"liveness_probe"`
SpiloPrivileged bool `json:"spilo_privileged,omitempty"`
@ -142,9 +141,9 @@ type KubernetesMetaConfiguration struct {
PodPriorityClassName string `json:"pod_priority_class_name,omitempty"`
// +kubebuilder:default="20m"
// timeout for successful migration of master pods from unschedulable node
MasterPodMoveTimeout Duration `json:"master_pod_move_timeout,omitempty"`
EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity,omitempty"`
PodAntiAffinityPreferredDuringScheduling bool `json:"pod_antiaffinity_preferred_during_scheduling,omitempty"`
MasterPodMoveTimeout *metav1.Duration `json:"master_pod_move_timeout,omitempty"`
EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity,omitempty"`
PodAntiAffinityPreferredDuringScheduling bool `json:"pod_antiaffinity_preferred_during_scheduling,omitempty"`
// +kubebuilder:default="kubernetes.io/hostname"
PodAntiAffinityTopologyKey string `json:"pod_antiaffinity_topology_key,omitempty"`
// +kubebuilder:validation:Enum=ordered_ready;parallel
@ -185,28 +184,28 @@ type PostgresPodResourcesDefaults struct {
type OperatorTimeouts struct {
// +kubebuilder:default="3s"
// interval to wait between consecutive attempts to check for some K8s resources
ResourceCheckInterval Duration `json:"resource_check_interval,omitempty"`
ResourceCheckInterval *metav1.Duration `json:"resource_check_interval,omitempty"`
// +kubebuilder:default="10m"
// timeout when waiting for the presence of a certain K8s resource
ResourceCheckTimeout Duration `json:"resource_check_timeout,omitempty"`
ResourceCheckTimeout *metav1.Duration `json:"resource_check_timeout,omitempty"`
// +kubebuilder:default="10m"
// timeout when waiting for pod role and cluster labels
PodLabelWaitTimeout Duration `json:"pod_label_wait_timeout,omitempty"`
PodLabelWaitTimeout *metav1.Duration `json:"pod_label_wait_timeout,omitempty"`
// +kubebuilder:default="10m"
// timeout when waiting for the Postgres pods to be deleted
PodDeletionWaitTimeout Duration `json:"pod_deletion_wait_timeout,omitempty"`
PodDeletionWaitTimeout *metav1.Duration `json:"pod_deletion_wait_timeout,omitempty"`
// +kubebuilder:default="4s"
// interval between consecutive attempts waiting for postgresql CRD to be created
ReadyWaitInterval Duration `json:"ready_wait_interval,omitempty"`
ReadyWaitInterval *metav1.Duration `json:"ready_wait_interval,omitempty"`
// +kubebuilder:default="30s"
// timeout for the complete postgres CRD creation
ReadyWaitTimeout Duration `json:"ready_wait_timeout,omitempty"`
ReadyWaitTimeout *metav1.Duration `json:"ready_wait_timeout,omitempty"`
// +kubebuilder:default="1s"
// interval between consecutive attempts of operator calling the Patroni API
PatroniAPICheckInterval Duration `json:"patroni_api_check_interval,omitempty"`
PatroniAPICheckInterval *metav1.Duration `json:"patroni_api_check_interval,omitempty"`
// +kubebuilder:default="5s"
// timeout when waiting for successful response from Patroni API
PatroniAPICheckTimeout Duration `json:"patroni_api_check_timeout,omitempty"`
PatroniAPICheckTimeout *metav1.Duration `json:"patroni_api_check_timeout,omitempty"`
}
// LoadBalancerConfiguration defines the LB configuration
@ -283,7 +282,7 @@ type TeamsAPIConfiguration struct {
PamRoleName string `json:"pam_role_name,omitempty"`
// +kubebuilder:default="https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"
PamConfiguration string `json:"pam_configuration,omitempty"`
// +kubebuilder:default="[\"admin\", \"cron_admin\"]"
// +kubebuilder:default={"admin", "cron_admin"}
ProtectedRoles []string `json:"protected_role_names,omitempty"`
PostgresSuperuserTeams []string `json:"postgres_superuser_teams,omitempty"`
// +kubebuilder:default=true
@ -419,16 +418,16 @@ type OperatorConfigurationData struct {
Workers uint32 `json:"workers,omitempty"`
// +kubebuilder:default="30m"
// period between consecutive sync requests
ResyncPeriod Duration `json:"resync_period,omitempty"`
ResyncPeriod *metav1.Duration `json:"resync_period,omitempty"`
// +kubebuilder:default="5m"
// period between consecutive repair requests
RepairPeriod Duration `json:"repair_period,omitempty"`
RepairPeriod *metav1.Duration `json:"repair_period,omitempty"`
// +kubebuilder:default=true
EnableMaintenanceWindows *bool `json:"enable_maintenance_windows,omitempty"`
// +kubebuilder:validation:Schemaless
// +kubebuilder:validation:Type=array
MaintenanceWindows []MaintenanceWindow `json:"maintenance_windows,omitempty"`
SetMemoryRequestToLimit bool `json:"set_memory_request_to_limit,omitempty"`
// +kubebuilder:validation:items:Pattern=`^\ *((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\d):([0-5]?\d)|(2[0-3]|[01]?\d):([0-5]?\d))-((2[0-3]|[01]?\d):([0-5]?\d)|(2[0-3]|[01]?\d):([0-5]?\d))\ *$`
MaintenanceWindows []string `json:"maintenance_windows,omitempty"`
SetMemoryRequestToLimit bool `json:"set_memory_request_to_limit,omitempty"`
// +kubebuilder:default=true
ShmVolume *bool `json:"enable_shm_volume,omitempty"`
SidecarImages map[string]string `json:"sidecar_docker_images,omitempty"` // deprecated in favour of SidecarContainers
@ -477,6 +476,3 @@ type OperatorConfigurationData struct {
IgnoreInstanceLimitsAnnotationKey string `json:"ignore_instance_limits_annotation_key,omitempty"`
IgnoreResourcesLimitsAnnotationKey string `json:"ignore_resources_limits_annotation_key,omitempty"`
}
// Duration shortens this frequently used name
type Duration time.Duration

View File

@ -4,6 +4,8 @@ kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
labels:
app.kubernetes.io/name: postgres-operator
name: operatorconfigurations.acid.zalan.do
spec:
group: acid.zalan.do
@ -445,8 +447,7 @@ spec:
default: 20m
description: timeout for successful migration of master pods from
unschedulable node
format: int64
type: integer
type: string
node_readiness_label:
additionalProperties:
type: string
@ -519,8 +520,7 @@ spec:
default: 5m
description: Postgres pods are terminated forcefully after this
timeout
format: int64
type: integer
type: string
secret_name_template:
default: '{username}.{cluster}.credentials.{tprkind}.{tprgroup}'
description: |-
@ -704,6 +704,10 @@ spec:
type: integer
type: object
maintenance_windows:
items:
pattern: ^\ *((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\d):([0-5]?\d)|(2[0-3]|[01]?\d):([0-5]?\d))-((2[0-3]|[01]?\d):([0-5]?\d)|(2[0-3]|[01]?\d):([0-5]?\d))\
*$
type: string
type: array
major_version_upgrade:
description: MajorVersionUpgradeConfiguration defines how to execute
@ -777,13 +781,11 @@ spec:
repair_period:
default: 5m
description: period between consecutive repair requests
format: int64
type: integer
type: string
resync_period:
default: 30m
description: period between consecutive sync requests
format: int64
type: integer
type: string
scalyr:
description: ScalyrConfiguration defines the configuration for ScalyrAPI
properties:
@ -849,7 +851,9 @@ spec:
type: string
type: array
protected_role_names:
default: '["admin", "cron_admin"]'
default:
- admin
- cron_admin
items:
type: string
type: array
@ -877,48 +881,40 @@ spec:
default: 1s
description: interval between consecutive attempts of operator
calling the Patroni API
format: int64
type: integer
type: string
patroni_api_check_timeout:
default: 5s
description: timeout when waiting for successful response from
Patroni API
format: int64
type: integer
type: string
pod_deletion_wait_timeout:
default: 10m
description: timeout when waiting for the Postgres pods to be
deleted
format: int64
type: integer
type: string
pod_label_wait_timeout:
default: 10m
description: timeout when waiting for pod role and cluster labels
format: int64
type: integer
type: string
ready_wait_interval:
default: 4s
description: interval between consecutive attempts waiting for
postgresql CRD to be created
format: int64
type: integer
type: string
ready_wait_timeout:
default: 30s
description: timeout for the complete postgres CRD creation
format: int64
type: integer
type: string
resource_check_interval:
default: 3s
description: interval to wait between consecutive attempts to
check for some K8s resources
format: int64
type: integer
type: string
resource_check_timeout:
default: 10m
description: timeout when waiting for the presence of a certain
K8s resource
format: int64
type: integer
type: string
type: object
users:
description: PostgresUsersConfiguration defines the system users of

View File

@ -11,6 +11,7 @@ import (
// +k8s:deepcopy-gen=true
// +kubebuilder:resource:shortName=pgteam,categories=all
// +kubebuilder:subresource:status
// +kubebuilder:metadata:labels=app.kubernetes.io/name=postgres-operator
type PostgresTeam struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`

View File

@ -4,6 +4,8 @@ kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
labels:
app.kubernetes.io/name: postgres-operator
name: postgresqls.acid.zalan.do
spec:
group: acid.zalan.do

View File

@ -24,6 +24,7 @@ import (
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`,description="Age of the PostgreSQL cluster"
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.PostgresClusterStatus`,description="Current sync status of postgresql resource"
// +kubebuilder:subresource:status
// +kubebuilder:metadata:labels=app.kubernetes.io/name=postgres-operator
type Postgresql struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"`

View File

@ -163,6 +163,11 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura
*out = new(bool)
**out = **in
}
if in.PodTerminateGracePeriod != nil {
in, out := &in.PodTerminateGracePeriod, &out.PodTerminateGracePeriod
*out = new(metav1.Duration)
**out = **in
}
if in.LivenessProbe != nil {
in, out := &in.LivenessProbe, &out.LivenessProbe
*out = new(corev1.Probe)
@ -280,6 +285,11 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura
}
}
out.PodEnvironmentConfigMap = in.PodEnvironmentConfigMap
if in.MasterPodMoveTimeout != nil {
in, out := &in.MasterPodMoveTimeout, &out.MasterPodMoveTimeout
*out = new(metav1.Duration)
**out = **in
}
if in.PersistentVolumeClaimRetentionPolicy != nil {
in, out := &in.PersistentVolumeClaimRetentionPolicy, &out.PersistentVolumeClaimRetentionPolicy
*out = make(map[string]string, len(*in))
@ -433,6 +443,16 @@ func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.ResyncPeriod != nil {
in, out := &in.ResyncPeriod, &out.ResyncPeriod
*out = new(metav1.Duration)
**out = **in
}
if in.RepairPeriod != nil {
in, out := &in.RepairPeriod, &out.RepairPeriod
*out = new(metav1.Duration)
**out = **in
}
if in.EnableMaintenanceWindows != nil {
in, out := &in.EnableMaintenanceWindows, &out.EnableMaintenanceWindows
*out = new(bool)
@ -440,10 +460,8 @@ func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData
}
if in.MaintenanceWindows != nil {
in, out := &in.MaintenanceWindows, &out.MaintenanceWindows
*out = make([]MaintenanceWindow, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.ShmVolume != nil {
in, out := &in.ShmVolume, &out.ShmVolume
@ -468,7 +486,7 @@ func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData
in.MajorVersionUpgrade.DeepCopyInto(&out.MajorVersionUpgrade)
in.Kubernetes.DeepCopyInto(&out.Kubernetes)
out.PostgresPodResources = in.PostgresPodResources
out.Timeouts = in.Timeouts
in.Timeouts.DeepCopyInto(&out.Timeouts)
in.LoadBalancer.DeepCopyInto(&out.LoadBalancer)
out.AWSGCP = in.AWSGCP
in.OperatorDebug.DeepCopyInto(&out.OperatorDebug)
@ -584,6 +602,46 @@ func (in *OperatorLogicalBackupConfiguration) DeepCopy() *OperatorLogicalBackupC
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OperatorTimeouts) DeepCopyInto(out *OperatorTimeouts) {
*out = *in
if in.ResourceCheckInterval != nil {
in, out := &in.ResourceCheckInterval, &out.ResourceCheckInterval
*out = new(metav1.Duration)
**out = **in
}
if in.ResourceCheckTimeout != nil {
in, out := &in.ResourceCheckTimeout, &out.ResourceCheckTimeout
*out = new(metav1.Duration)
**out = **in
}
if in.PodLabelWaitTimeout != nil {
in, out := &in.PodLabelWaitTimeout, &out.PodLabelWaitTimeout
*out = new(metav1.Duration)
**out = **in
}
if in.PodDeletionWaitTimeout != nil {
in, out := &in.PodDeletionWaitTimeout, &out.PodDeletionWaitTimeout
*out = new(metav1.Duration)
**out = **in
}
if in.ReadyWaitInterval != nil {
in, out := &in.ReadyWaitInterval, &out.ReadyWaitInterval
*out = new(metav1.Duration)
**out = **in
}
if in.ReadyWaitTimeout != nil {
in, out := &in.ReadyWaitTimeout, &out.ReadyWaitTimeout
*out = new(metav1.Duration)
**out = **in
}
if in.PatroniAPICheckInterval != nil {
in, out := &in.PatroniAPICheckInterval, &out.PatroniAPICheckInterval
*out = new(metav1.Duration)
**out = **in
}
if in.PatroniAPICheckTimeout != nil {
in, out := &in.PatroniAPICheckTimeout, &out.PatroniAPICheckTimeout
*out = new(metav1.Duration)
**out = **in
}
return
}

View File

@ -138,7 +138,8 @@ func TestCreate(t *testing.T) {
var cluster = New(
Config{
OpConfig: config.Config{
PodManagementPolicy: "ordered_ready",
PodManagementPolicy: "ordered_ready",
PodTerminateGracePeriod: &metav1.Duration{Duration: 600 * time.Second},
Resources: config.Resources{
ClusterLabels: map[string]string{"application": "spilo"},
ClusterNameLabel: "cluster-name",
@ -147,8 +148,8 @@ func TestCreate(t *testing.T) {
DefaultMemoryRequest: "300Mi",
DefaultMemoryLimit: "300Mi",
PodRoleLabel: "spilo-role",
ResourceCheckInterval: time.Duration(3),
ResourceCheckTimeout: time.Duration(10),
ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second},
ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute},
},
EnableFinalizers: util.True(),
},

View File

@ -292,7 +292,7 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
if connectionPoolerSpec == nil {
connectionPoolerSpec = &acidv1.ConnectionPooler{}
}
gracePeriod := int64(c.OpConfig.PodTerminateGracePeriod.Seconds())
gracePeriod := int64(util.CoalesceDuration(c.OpConfig.PodTerminateGracePeriod, "5m").Seconds())
resources, err := c.generateResourceRequirements(
connectionPoolerSpec.Resources,
makeDefaultConnectionPoolerResources(&c.OpConfig),

View File

@ -1165,7 +1165,7 @@ func (c *Cluster) getPodEnvironmentSecretVariables() ([]v1.EnvVar, error) {
secret := &v1.Secret{}
var notFoundErr error
err := retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout,
err := retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration,
func() (bool, error) {
var err error
secret, err = c.KubeClient.Secrets(c.Namespace).Get(
@ -1498,7 +1498,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef
&tolerationSpec,
c.nodeAffinity(c.OpConfig.NodeReadinessLabel, spec.NodeAffinity),
spec.SchedulerName,
int64(c.OpConfig.PodTerminateGracePeriod.Seconds()),
int64(util.CoalesceDuration(c.OpConfig.PodTerminateGracePeriod, "5m").Seconds()),
c.OpConfig.PodServiceAccountName,
c.OpConfig.KubeIAMRole,
effectivePodPriorityClassName,
@ -2431,7 +2431,7 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1.CronJob, error) {
&tolerationsSpec,
c.nodeAffinity(c.OpConfig.NodeReadinessLabel, nil),
nil,
int64(c.OpConfig.PodTerminateGracePeriod.Seconds()),
int64(util.CoalesceDuration(c.OpConfig.PodTerminateGracePeriod, "5m").Seconds()),
c.OpConfig.PodServiceAccountName,
c.OpConfig.KubeIAMRole,
"",

View File

@ -6,7 +6,6 @@ import (
"reflect"
"sort"
"testing"
"time"
"github.com/stretchr/testify/assert"
@ -361,8 +360,8 @@ func TestPodEnvironmentSecretVariables(t *testing.T) {
opConfig: config.Config{
Resources: config.Resources{
PodEnvironmentSecret: testPodEnvironmentObjectNotExists,
ResourceCheckInterval: time.Duration(testResourceCheckInterval),
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval},
ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout},
},
},
err: fmt.Errorf("could not read Secret PodEnvironmentSecretName: still failing after %d retries: secret.core %q not found", maxRetries, testPodEnvironmentObjectNotExists),
@ -372,8 +371,8 @@ func TestPodEnvironmentSecretVariables(t *testing.T) {
opConfig: config.Config{
Resources: config.Resources{
PodEnvironmentSecret: testPodEnvironmentSecretNameAPIError,
ResourceCheckInterval: time.Duration(testResourceCheckInterval),
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval},
ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout},
},
},
err: fmt.Errorf("could not read Secret PodEnvironmentSecretName: Secret PodEnvironmentSecret API error"),
@ -383,8 +382,8 @@ func TestPodEnvironmentSecretVariables(t *testing.T) {
opConfig: config.Config{
Resources: config.Resources{
PodEnvironmentSecret: testPodEnvironmentSecretName,
ResourceCheckInterval: time.Duration(testResourceCheckInterval),
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval},
ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout},
},
},
envVars: []v1.EnvVar{
@ -848,8 +847,8 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) {
Name: testPodEnvironmentConfigMapName,
},
PodEnvironmentSecret: testPodEnvironmentSecretName,
ResourceCheckInterval: time.Duration(testResourceCheckInterval),
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval},
ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout},
},
},
cloneDescription: &acidv1.CloneDescription{},
@ -877,8 +876,8 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) {
Name: testPodEnvironmentConfigMapName,
},
PodEnvironmentSecret: testPodEnvironmentSecretName,
ResourceCheckInterval: time.Duration(testResourceCheckInterval),
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval},
ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout},
},
},
cloneDescription: &acidv1.CloneDescription{},
@ -968,8 +967,8 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) {
opConfig: config.Config{
Resources: config.Resources{
PodEnvironmentSecret: testPodEnvironmentSecretName,
ResourceCheckInterval: time.Duration(testResourceCheckInterval),
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval},
ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout},
},
WALES3Bucket: "global-s3-bucket",
},
@ -986,8 +985,8 @@ func TestGenerateSpiloPodEnvVars(t *testing.T) {
opConfig: config.Config{
Resources: config.Resources{
PodEnvironmentSecret: testPodEnvironmentSecretName,
ResourceCheckInterval: time.Duration(testResourceCheckInterval),
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval},
ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout},
},
WALES3Bucket: "global-s3-bucket",
},

View File

@ -334,7 +334,7 @@ func (c *Cluster) getPatroniConfig(pod *v1.Pod) (acidv1.Patroni, map[string]stri
pgParameters map[string]string
)
podName := util.NameFromMeta(pod.ObjectMeta)
err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval, c.OpConfig.PatroniAPICheckTimeout,
err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval.Duration, c.OpConfig.PatroniAPICheckTimeout.Duration,
func() (bool, error) {
var err error
patroniConfig, pgParameters, err = c.patroni.GetConfig(pod)
@ -355,7 +355,7 @@ func (c *Cluster) getPatroniConfig(pod *v1.Pod) (acidv1.Patroni, map[string]stri
func (c *Cluster) getPatroniMemberData(pod *v1.Pod) (patroni.MemberData, error) {
var memberData patroni.MemberData
err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval, c.OpConfig.PatroniAPICheckTimeout,
err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval.Duration, c.OpConfig.PatroniAPICheckTimeout.Duration,
func() (bool, error) {
var err error
memberData, err = c.patroni.GetMemberData(pod)
@ -506,7 +506,7 @@ func (c *Cluster) getSwitchoverCandidate(master *v1.Pod) (spec.NamespacedName, e
candidates := make([]patroni.ClusterMember, 0)
syncCandidates := make([]patroni.ClusterMember, 0)
err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval, c.OpConfig.PatroniAPICheckTimeout,
err := retryutil.Retry(c.OpConfig.PatroniAPICheckInterval.Duration, c.OpConfig.PatroniAPICheckTimeout.Duration,
func() (bool, error) {
var err error
members, err = c.patroni.GetClusterMembers(master)

View File

@ -16,6 +16,7 @@ import (
"github.com/zalando/postgres-operator/pkg/util/k8sutil"
"github.com/zalando/postgres-operator/pkg/util/patroni"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestGetSwitchoverCandidate(t *testing.T) {
@ -28,8 +29,8 @@ func TestGetSwitchoverCandidate(t *testing.T) {
var cluster = New(
Config{
OpConfig: config.Config{
PatroniAPICheckInterval: time.Duration(1),
PatroniAPICheckTimeout: time.Duration(5),
PatroniAPICheckInterval: &metav1.Duration{Duration: 1 * time.Second},
PatroniAPICheckTimeout: &metav1.Duration{Duration: 5 * time.Second},
},
}, k8sutil.KubernetesClient{}, acidv1.Postgresql{}, logger, eventRecorder)

View File

@ -234,7 +234,7 @@ func (c *Cluster) replaceStatefulSet(newStatefulSet *appsv1.StatefulSet) error {
// wait until the statefulset is truly deleted
c.logger.Debug("waiting for the statefulset to be deleted")
err = retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout,
err = retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration,
func() (bool, error) {
_, err2 := c.KubeClient.StatefulSets(oldStatefulset.Namespace).Get(context.TODO(), oldStatefulset.Name, metav1.GetOptions{})
if err2 == nil {
@ -550,7 +550,7 @@ func (c *Cluster) deletePrimaryPodDisruptionBudget() error {
c.logger.Infof("pod disruption budget %q has been deleted", util.NameFromMeta(c.PrimaryPodDisruptionBudget.ObjectMeta))
c.PrimaryPodDisruptionBudget = nil
err = retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout,
err = retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration,
func() (bool, error) {
_, err2 := c.KubeClient.PodDisruptionBudgets(pdbName.Namespace).Get(context.TODO(), pdbName.Name, metav1.GetOptions{})
if err2 == nil {
@ -588,7 +588,7 @@ func (c *Cluster) deleteCriticalOpPodDisruptionBudget() error {
c.logger.Infof("pod disruption budget %q has been deleted", util.NameFromMeta(c.CriticalOpPodDisruptionBudget.ObjectMeta))
c.CriticalOpPodDisruptionBudget = nil
err = retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout,
err = retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration,
func() (bool, error) {
_, err2 := c.KubeClient.PodDisruptionBudgets(pdbName.Namespace).Get(context.TODO(), pdbName.Name, metav1.GetOptions{})
if err2 == nil {

View File

@ -101,8 +101,8 @@ func TestSyncStatefulSetsAnnotations(t *testing.T) {
DefaultMemoryLimit: "300Mi",
InheritedAnnotations: []string{inheritedAnnotation},
PodRoleLabel: "spilo-role",
ResourceCheckInterval: time.Duration(3),
ResourceCheckTimeout: time.Duration(10),
ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second},
ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute},
},
},
}, client, pg, logger, eventRecorder)
@ -187,8 +187,8 @@ func TestPodAnnotationsSync(t *testing.T) {
var cluster = New(
Config{
OpConfig: config.Config{
PatroniAPICheckInterval: time.Duration(1),
PatroniAPICheckTimeout: time.Duration(5),
PatroniAPICheckInterval: &metav1.Duration{Duration: 1 * time.Second},
PatroniAPICheckTimeout: &metav1.Duration{Duration: 5 * time.Second},
PodManagementPolicy: "ordered_ready",
CustomPodAnnotations: customPodAnnotations,
ConnectionPooler: config.ConnectionPooler{
@ -207,8 +207,8 @@ func TestPodAnnotationsSync(t *testing.T) {
DefaultMemoryLimit: "300Mi",
MaxInstances: -1,
PodRoleLabel: "spilo-role",
ResourceCheckInterval: time.Duration(3),
ResourceCheckTimeout: time.Duration(10),
ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second},
ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute},
},
},
}, client, pg, logger, eventRecorder)
@ -381,8 +381,8 @@ func TestCheckAndSetGlobalPostgreSQLConfiguration(t *testing.T) {
DefaultMemoryRequest: "300Mi",
DefaultMemoryLimit: "300Mi",
PodRoleLabel: "spilo-role",
ResourceCheckInterval: time.Duration(3),
ResourceCheckTimeout: time.Duration(10),
ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second},
ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute},
},
},
}, client, pg, logger, eventRecorder)
@ -694,8 +694,8 @@ func TestSyncStandbyClusterConfiguration(t *testing.T) {
var cluster = New(
Config{
OpConfig: config.Config{
PatroniAPICheckInterval: time.Duration(1),
PatroniAPICheckTimeout: time.Duration(5),
PatroniAPICheckInterval: &metav1.Duration{Duration: 1 * time.Second},
PatroniAPICheckTimeout: &metav1.Duration{Duration: 5 * time.Second},
PodManagementPolicy: "ordered_ready",
Resources: config.Resources{
ClusterLabels: map[string]string{"application": applicationLabel},
@ -707,8 +707,8 @@ func TestSyncStandbyClusterConfiguration(t *testing.T) {
MinInstances: int32(-1),
MaxInstances: int32(-1),
PodRoleLabel: "spilo-role",
ResourceCheckInterval: time.Duration(3),
ResourceCheckTimeout: time.Duration(10),
ResourceCheckInterval: &metav1.Duration{Duration: 3 * time.Second},
ResourceCheckTimeout: &metav1.Duration{Duration: 10 * time.Minute},
},
},
}, client, pg, logger, eventRecorder)

View File

@ -342,7 +342,7 @@ func (c *Cluster) annotationsSet(annotations map[string]string) map[string]strin
}
func (c *Cluster) waitForPodLabel(podEvents chan PodEvent, stopCh chan struct{}, role *PostgresRole) (*v1.Pod, error) {
timeout := time.After(c.OpConfig.PodLabelWaitTimeout)
timeout := time.After(c.OpConfig.PodLabelWaitTimeout.Duration)
for {
select {
case podEvent := <-podEvents:
@ -364,7 +364,7 @@ func (c *Cluster) waitForPodLabel(podEvents chan PodEvent, stopCh chan struct{},
}
func (c *Cluster) waitForPodDeletion(podEvents chan PodEvent) error {
timeout := time.After(c.OpConfig.PodDeletionWaitTimeout)
timeout := time.After(c.OpConfig.PodDeletionWaitTimeout.Duration)
for {
select {
case podEvent := <-podEvents:
@ -378,7 +378,7 @@ func (c *Cluster) waitForPodDeletion(podEvents chan PodEvent) error {
}
func (c *Cluster) waitStatefulsetReady() error {
return retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout,
return retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration,
func() (bool, error) {
listOptions := metav1.ListOptions{
LabelSelector: c.labelsSet(false).String(),
@ -428,7 +428,7 @@ func (c *Cluster) _waitPodLabelsReady(anyReplica bool) error {
c.logger.Debug("Waiting for any replica pod to become ready")
}
err := retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout,
err := retryutil.Retry(c.OpConfig.ResourceCheckInterval.Duration, c.OpConfig.ResourceCheckTimeout.Duration,
func() (bool, error) {
masterCount := 0
if !anyReplica {

View File

@ -297,8 +297,8 @@ func newInheritedAnnotationsCluster(client k8sutil.KubernetesClient) (*Cluster,
cluster := New(
Config{
OpConfig: config.Config{
PatroniAPICheckInterval: time.Duration(1),
PatroniAPICheckTimeout: time.Duration(5),
PatroniAPICheckInterval: &metav1.Duration{Duration: 1 * time.Second},
PatroniAPICheckTimeout: &metav1.Duration{Duration: 5 * time.Second},
KubernetesUseConfigMaps: true,
ConnectionPooler: config.ConnectionPooler{
ConnectionPoolerDefaultCPURequest: "100m",
@ -318,8 +318,8 @@ func newInheritedAnnotationsCluster(client k8sutil.KubernetesClient) (*Cluster,
DefaultMemoryLimit: "300Mi",
InheritedAnnotations: []string{"owned-by"},
PodRoleLabel: "spilo-role",
ResourceCheckInterval: time.Duration(testResourceCheckInterval),
ResourceCheckTimeout: time.Duration(testResourceCheckTimeout),
ResourceCheckInterval: &metav1.Duration{Duration: testResourceCheckInterval},
ResourceCheckTimeout: &metav1.Duration{Duration: testResourceCheckTimeout},
MinInstances: -1,
MaxInstances: -1,
},

View File

@ -152,7 +152,7 @@ func (c *Controller) nodeDelete(obj interface{}) {
func (c *Controller) moveMasterPodsOffNode(node *v1.Node) {
// retry to move master until configured timeout is reached
err := retryutil.Retry(1*time.Minute, c.opConfig.MasterPodMoveTimeout,
err := retryutil.Retry(1*time.Minute, c.opConfig.MasterPodMoveTimeout.Duration,
func() (bool, error) {
err := c.attemptToMoveMasterPodsOffNode(node)
if err != nil {

View File

@ -4,8 +4,6 @@ import (
"context"
"fmt"
"time"
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
"github.com/zalando/postgres-operator/pkg/util"
"github.com/zalando/postgres-operator/pkg/util/config"
@ -44,23 +42,14 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
result.MaxInstances = fromCRD.MaxInstances
result.IgnoreInstanceLimitsAnnotationKey = fromCRD.IgnoreInstanceLimitsAnnotationKey
result.IgnoreResourcesLimitsAnnotationKey = fromCRD.IgnoreResourcesLimitsAnnotationKey
result.ResyncPeriod = util.CoalesceDuration(time.Duration(fromCRD.ResyncPeriod), "30m")
result.RepairPeriod = util.CoalesceDuration(time.Duration(fromCRD.RepairPeriod), "5m")
result.ResyncPeriod = util.CoalesceDuration(fromCRD.ResyncPeriod, "30m")
result.RepairPeriod = util.CoalesceDuration(fromCRD.RepairPeriod, "5m")
result.SetMemoryRequestToLimit = fromCRD.SetMemoryRequestToLimit
result.ShmVolume = util.CoalesceBool(fromCRD.ShmVolume, util.True())
result.SidecarImages = fromCRD.SidecarImages
result.SidecarContainers = fromCRD.SidecarContainers
result.EnableMaintenanceWindows = util.CoalesceBool(fromCRD.EnableMaintenanceWindows, util.True())
if len(fromCRD.MaintenanceWindows) > 0 {
result.MaintenanceWindows = make([]string, 0, len(fromCRD.MaintenanceWindows))
for _, window := range fromCRD.MaintenanceWindows {
w, err := window.MarshalJSON()
if err != nil {
panic(fmt.Errorf("could not marshal configured maintenance window: %v", err))
}
result.MaintenanceWindows = append(result.MaintenanceWindows, string(w))
}
}
result.MaintenanceWindows = fromCRD.MaintenanceWindows
// user config
result.SuperUsername = util.Coalesce(fromCRD.PostgresUsersConfiguration.SuperUsername, "postgres")
@ -84,7 +73,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
result.PodServiceAccountRoleBindingDefinition = fromCRD.Kubernetes.PodServiceAccountRoleBindingDefinition
result.PodEnvironmentConfigMap = fromCRD.Kubernetes.PodEnvironmentConfigMap
result.PodEnvironmentSecret = fromCRD.Kubernetes.PodEnvironmentSecret
result.PodTerminateGracePeriod = util.CoalesceDuration(time.Duration(fromCRD.Kubernetes.PodTerminateGracePeriod), "5m")
result.PodTerminateGracePeriod = util.CoalesceDuration(fromCRD.Kubernetes.PodTerminateGracePeriod, "5m")
result.LivenessProbe = fromCRD.Kubernetes.LivenessProbe
result.SpiloPrivileged = fromCRD.Kubernetes.SpiloPrivileged
result.SpiloAllowPrivilegeEscalation = util.CoalesceBool(fromCRD.Kubernetes.SpiloAllowPrivilegeEscalation, util.True())
@ -138,7 +127,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
result.EnableSecretsDeletion = util.CoalesceBool(fromCRD.Kubernetes.EnableSecretsDeletion, util.True())
result.EnablePersistentVolumeClaimDeletion = util.CoalesceBool(fromCRD.Kubernetes.EnablePersistentVolumeClaimDeletion, util.True())
result.EnableReadinessProbe = fromCRD.Kubernetes.EnableReadinessProbe
result.MasterPodMoveTimeout = util.CoalesceDuration(time.Duration(fromCRD.Kubernetes.MasterPodMoveTimeout), "10m")
result.MasterPodMoveTimeout = util.CoalesceDuration(fromCRD.Kubernetes.MasterPodMoveTimeout, "10m")
result.EnablePodAntiAffinity = fromCRD.Kubernetes.EnablePodAntiAffinity
result.PodAntiAffinityTopologyKey = util.Coalesce(fromCRD.Kubernetes.PodAntiAffinityTopologyKey, "kubernetes.io/hostname")
result.PodAntiAffinityPreferredDuringScheduling = fromCRD.Kubernetes.PodAntiAffinityPreferredDuringScheduling
@ -155,14 +144,14 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
result.MaxMemoryRequest = fromCRD.PostgresPodResources.MaxMemoryRequest
// timeout config
result.ResourceCheckInterval = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.ResourceCheckInterval), "3s")
result.ResourceCheckTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.ResourceCheckTimeout), "10m")
result.PodLabelWaitTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.PodLabelWaitTimeout), "10m")
result.PodDeletionWaitTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.PodDeletionWaitTimeout), "10m")
result.ReadyWaitInterval = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.ReadyWaitInterval), "4s")
result.ReadyWaitTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.ReadyWaitTimeout), "30s")
result.PatroniAPICheckInterval = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.PatroniAPICheckInterval), "1s")
result.PatroniAPICheckTimeout = util.CoalesceDuration(time.Duration(fromCRD.Timeouts.PatroniAPICheckTimeout), "5s")
result.ResourceCheckInterval = util.CoalesceDuration(fromCRD.Timeouts.ResourceCheckInterval, "3s")
result.ResourceCheckTimeout = util.CoalesceDuration(fromCRD.Timeouts.ResourceCheckTimeout, "10m")
result.PodLabelWaitTimeout = util.CoalesceDuration(fromCRD.Timeouts.PodLabelWaitTimeout, "10m")
result.PodDeletionWaitTimeout = util.CoalesceDuration(fromCRD.Timeouts.PodDeletionWaitTimeout, "10m")
result.ReadyWaitInterval = util.CoalesceDuration(fromCRD.Timeouts.ReadyWaitInterval, "4s")
result.ReadyWaitTimeout = util.CoalesceDuration(fromCRD.Timeouts.ReadyWaitTimeout, "30s")
result.PatroniAPICheckInterval = util.CoalesceDuration(fromCRD.Timeouts.PatroniAPICheckInterval, "1s")
result.PatroniAPICheckTimeout = util.CoalesceDuration(fromCRD.Timeouts.PatroniAPICheckTimeout, "5s")
// load balancer config
result.DbHostedZone = util.Coalesce(fromCRD.LoadBalancer.DbHostedZone, "db.example.com")

View File

@ -27,7 +27,7 @@ import (
func (c *Controller) clusterResync(stopCh <-chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
ticker := time.NewTicker(c.opConfig.ResyncPeriod)
ticker := time.NewTicker(c.opConfig.ResyncPeriod.Duration)
for {
select {

View File

@ -3,33 +3,33 @@ package config
import (
"encoding/json"
"strings"
"time"
"fmt"
"github.com/zalando/postgres-operator/pkg/spec"
"github.com/zalando/postgres-operator/pkg/util/constants"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// CRD describes CustomResourceDefinition specific configuration parameters
type CRD struct {
ReadyWaitInterval time.Duration `name:"ready_wait_interval" default:"4s"`
ReadyWaitTimeout time.Duration `name:"ready_wait_timeout" default:"30s"`
ResyncPeriod time.Duration `name:"resync_period" default:"30m"`
RepairPeriod time.Duration `name:"repair_period" default:"5m"`
EnableCRDRegistration *bool `name:"enable_crd_registration" default:"true"`
CRDCategories []string `name:"crd_categories" default:"all"`
ReadyWaitInterval *metav1.Duration `name:"ready_wait_interval" default:"4s"`
ReadyWaitTimeout *metav1.Duration `name:"ready_wait_timeout" default:"30s"`
ResyncPeriod *metav1.Duration `name:"resync_period" default:"30m"`
RepairPeriod *metav1.Duration `name:"repair_period" default:"5m"`
EnableCRDRegistration *bool `name:"enable_crd_registration" default:"true"`
CRDCategories []string `name:"crd_categories" default:"all"`
}
// Resources describes kubernetes resource specific configuration parameters
type Resources struct {
EnableOwnerReferences *bool `name:"enable_owner_references" default:"false"`
ResourceCheckInterval time.Duration `name:"resource_check_interval" default:"3s"`
ResourceCheckTimeout time.Duration `name:"resource_check_timeout" default:"10m"`
PodLabelWaitTimeout time.Duration `name:"pod_label_wait_timeout" default:"10m"`
PodDeletionWaitTimeout time.Duration `name:"pod_deletion_wait_timeout" default:"10m"`
PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
ResourceCheckInterval *metav1.Duration `name:"resource_check_interval" default:"3s"`
ResourceCheckTimeout *metav1.Duration `name:"resource_check_timeout" default:"10m"`
PodLabelWaitTimeout *metav1.Duration `name:"pod_label_wait_timeout" default:"10m"`
PodDeletionWaitTimeout *metav1.Duration `name:"pod_deletion_wait_timeout" default:"10m"`
PodTerminateGracePeriod *metav1.Duration `name:"pod_terminate_grace_period" default:"5m"`
LivenessProbe *v1.Probe `name:"-"`
SpiloRunAsUser *int64 `name:"spilo_runasuser"`
SpiloRunAsGroup *int64 `name:"spilo_runasgroup"`
@ -188,7 +188,7 @@ type Config struct {
// value of this string must be valid JSON or YAML; see initPodServiceAccount
PodServiceAccountDefinition string `name:"pod_service_account_definition" default:""`
PodServiceAccountRoleBindingDefinition string `name:"pod_service_account_role_binding_definition" default:""`
MasterPodMoveTimeout time.Duration `name:"master_pod_move_timeout" default:"20m"`
MasterPodMoveTimeout *metav1.Duration `name:"master_pod_move_timeout" default:"20m"`
DbHostedZone string `name:"db_hosted_zone" default:"db.example.com"`
AWSRegion string `name:"aws_region" default:"eu-central-1"`
WALES3Bucket string `name:"wal_s3_bucket"`
@ -242,7 +242,7 @@ type Config struct {
RingLogLines int `name:"ring_log_lines" default:"100"`
ClusterHistoryEntries int `name:"cluster_history_entries" default:"1000"`
TeamAPIRoleConfiguration map[string]string `name:"team_api_role_configuration" default:"log_statement:all"`
PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
PodTerminateGracePeriod *metav1.Duration `name:"pod_terminate_grace_period" default:"5m"`
PodManagementPolicy string `name:"pod_management_policy" default:"ordered_ready"`
EnableReadinessProbe bool `name:"enable_readiness_probe" default:"false"`
ProtectedRoles []string `name:"protected_role_names" default:"admin,cron_admin"`
@ -258,8 +258,8 @@ type Config struct {
MajorVersionUpgradeTeamAllowList []string `name:"major_version_upgrade_team_allow_list" default:""`
MinimalMajorVersion string `name:"minimal_major_version" default:"14"`
TargetMajorVersion string `name:"target_major_version" default:"18"`
PatroniAPICheckInterval time.Duration `name:"patroni_api_check_interval" default:"1s"`
PatroniAPICheckTimeout time.Duration `name:"patroni_api_check_timeout" default:"5s"`
PatroniAPICheckInterval *metav1.Duration `name:"patroni_api_check_interval" default:"1s"`
PatroniAPICheckTimeout *metav1.Duration `name:"patroni_api_check_timeout" default:"5s"`
EnablePatroniFailsafeMode *bool `name:"enable_patroni_failsafe_mode" default:"false"`
EnableSecretsDeletion *bool `name:"enable_secrets_deletion" default:"true"`
EnablePersistentVolumeClaimDeletion *bool `name:"enable_persistent_volume_claim_deletion" default:"true"`

View File

@ -230,16 +230,16 @@ var newFromMapTests = []struct {
{
description: "duration parsing",
input: map[string]string{
"ready_wait_interval": "10s",
"ready_wait_timeout": "1m",
"patroni_api_check_interval": "1s",
"patroni_api_check_timeout": "5s",
},
expectPanic: false,
validateFunc: func(t *testing.T, cfg *Config) {
if cfg.ReadyWaitInterval.Seconds() != 10 {
t.Errorf("expected ReadyWaitInterval=10s, got %v", cfg.ReadyWaitInterval)
if cfg.PatroniAPICheckInterval.Seconds() != 1 {
t.Errorf("expected check interval of 1s, got %.0fs", cfg.PatroniAPICheckInterval.Seconds())
}
if cfg.ReadyWaitTimeout.Minutes() != 1 {
t.Errorf("expected ReadyWaitTimeout=1m, got %v", cfg.ReadyWaitTimeout)
if cfg.PatroniAPICheckTimeout.Seconds() != 5 {
t.Errorf("expected check timeout of 5s, got %.0fs", cfg.PatroniAPICheckTimeout.Seconds())
}
},
},

View File

@ -7,6 +7,8 @@ import (
"strconv"
"strings"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type decoder interface {
@ -101,13 +103,7 @@ func processField(value string, field reflect.Value) error {
val int64
err error
)
if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" {
var d time.Duration
d, err = time.ParseDuration(value)
val = int64(d)
} else {
val, err = strconv.ParseInt(value, 0, typ.Bits())
}
val, err = strconv.ParseInt(value, 0, typ.Bits())
if err != nil {
return err
}
@ -165,6 +161,15 @@ func processField(value string, field reflect.Value) error {
mp.SetMapIndex(k, v)
}
field.Set(mp)
case reflect.Struct:
if typ.Name() == "Duration" {
var d time.Duration
d, err := time.ParseDuration(value)
if err != nil {
return err
}
field.Set(reflect.ValueOf(metav1.Duration{Duration: d}))
}
}
return nil

View File

@ -311,14 +311,14 @@ func CoalesceBool(val, defaultVal *bool) *bool {
return val
}
// CoalesceDuration works like coalesce but for time.Duration
func CoalesceDuration(val time.Duration, defaultVal string) time.Duration {
if val == 0 {
// CoalesceDuration works like coalesce but for metav1.Duration
func CoalesceDuration(val *metav1.Duration, defaultVal string) *metav1.Duration {
if val == nil || val.Duration == 0 {
duration, err := time.ParseDuration(defaultVal)
if err != nil {
panic(err)
}
return duration
return &metav1.Duration{Duration: duration}
}
return val
}