From c4889a3c827ebdd4c0a566c47645574c276025dd Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Fri, 15 Nov 2019 13:01:03 +0100 Subject: [PATCH] add toggle to disable creation of CRD validation and document it --- .../templates/customrresourcedefinition.yaml | 4 +- charts/postgres-operator/values-crd.yaml | 2 + charts/postgres-operator/values.yaml | 2 + docs/administrator.md | 24 + docs/quickstart.md | 18 +- docs/reference/operator_parameters.md | 5 + manifests/configmap.yaml | 1 + manifests/operatorconfiguration.crd.yaml | 3 +- ...gresql-operator-default-configuration.yaml | 1 + manifests/postgresql.crd.yaml | 3 +- pkg/apis/acid.zalan.do/v1/crds.go | 1572 +++++++++-------- .../v1/operator_configuration_type.go | 1 + pkg/controller/controller.go | 6 +- pkg/controller/operator_config.go | 1 + pkg/controller/util.go | 10 +- pkg/util/config/config.go | 9 +- 16 files changed, 856 insertions(+), 806 deletions(-) diff --git a/charts/postgres-operator/templates/customrresourcedefinition.yaml b/charts/postgres-operator/templates/customrresourcedefinition.yaml index f0a0bcfd2..c024ed62f 100644 --- a/charts/postgres-operator/templates/customrresourcedefinition.yaml +++ b/charts/postgres-operator/templates/customrresourcedefinition.yaml @@ -54,6 +54,7 @@ spec: scope: Namespaced subresources: status: {} + version: v1 validation: openAPIV3Schema: type: object @@ -364,7 +365,6 @@ spec: type: string subPath: type: string - version: v1 --- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition @@ -409,6 +409,7 @@ spec: scope: Namespaced subresources: status: {} + version: v1 validation: openAPIV3Schema: type: object @@ -657,5 +658,4 @@ spec: pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' scalyr_server_url: type: string - version: v1 {{ end }} diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index af05ae56c..32f3c6e55 100644 --- a/charts/postgres-operator/values-crd.yaml +++ b/charts/postgres-operator/values-crd.yaml @@ -17,6 +17,8 @@ configTarget: "OperatorConfigurationCRD" # general top-level configuration parameters configGeneral: + # choose if deployment creates/updates CRDs with OpenAPIV3Validation + enable_crd_validation: true # start any new database pod without limitations on shm memory enable_shm_volume: true # etcd connection string for Patroni. Empty uses K8s-native DCS. diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index b572b5844..a884dcf4f 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -17,6 +17,8 @@ configTarget: "ConfigMap" # general configuration parameters configGeneral: + # choose if deployment creates/updates CRDs with OpenAPIV3Validation + enable_crd_validation: "true" # start any new database pod without limitations on shm memory enable_shm_volume: "true" # etcd connection string for Patroni. Empty uses K8s-native DCS. diff --git a/docs/administrator.md b/docs/administrator.md index 46b4ce71a..24e73478b 100644 --- a/docs/administrator.md +++ b/docs/administrator.md @@ -3,6 +3,30 @@ Learn how to configure and manage the Postgres Operator in your Kubernetes (K8s) environment. +## CRD Validation + +[CustomResourceDefinitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) +will be registered with schema validation by default when the operator is +deployed. The `OperatorConfiguration` CRD will only get created if the +`POSTGRES_OPERATOR_CONFIGURATION_OBJECT` [environment variable](../manifests/postgres-operator.yaml#L36) +in the deployment yaml is set and not empty. + +When submitting manifests of [`postgresql`](../manifests/postgresql.crd.yaml) or +[`OperatorConfiguration`](../manifests/operatorconfiguration.crd.yaml) custom +resources with kubectl, validation can be bypassed with `--validate=false`. The +operator can also be configured to not register CRDs with validation on `ADD` or +`UPDATE` events. Running instances are not affected when enabling the validation +afterwards unless the manifests is not changed then. Note, that the provided CRD +manifests contain the validation for users to understand what schema is +enforced. + +Once the validation is enabled it can only be disabled manually by editing or +patching the CRD manifest: + +```bash +zk8 patch crd postgresqls.acid.zalan.do -p '{"spec":{"validation": null}}' +``` + ## Namespaces ### Select the namespace to deploy to diff --git a/docs/quickstart.md b/docs/quickstart.md index aa962ddaf..f5546fc98 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -119,15 +119,15 @@ kubectl get pod -l app.kubernetes.io/name=postgres-operator kubectl create -f manifests/minimal-postgres-manifest.yaml ``` -After the cluster manifest is submitted the operator will create Service and -Endpoint resources and a StatefulSet which spins up new Pod(s) given the number -of instances specified in the manifest. All resources are named like the -cluster. The database pods can be identified by their number suffix, starting -from `-0`. They run the [Spilo](https://github.com/zalando/spilo) container -image by Zalando. As for the services and endpoints, there will be one for the -master pod and another one for all the replicas (`-repl` suffix). Check if all -components are coming up. Use the label `application=spilo` to filter and list -the label `spilo-role` to see who is currently the master. +After the cluster manifest is submitted and passed the validation the operator +will create Service and Endpoint resources and a StatefulSet which spins up new +Pod(s) given the number of instances specified in the manifest. All resources +are named like the cluster. The database pods can be identified by their number +suffix, starting from `-0`. They run the [Spilo](https://github.com/zalando/spilo) +container image by Zalando. As for the services and endpoints, there will be one +for the master pod and another one for all the replicas (`-repl` suffix). Check +if all components are coming up. Use the label `application=spilo` to filter and +list the label `spilo-role` to see who is currently the master. ```bash # check the deployed cluster diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index 5b9b70f61..4a53ea3a4 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -69,6 +69,11 @@ Variable names are underscore-separated words. Those are top-level keys, containing both leaf keys and groups. +* **enable_crd_validation** + toggles if the operator will create or update CRDs with + [OpenAPI v3 schema validation](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#validation) + The default is `true`. + * **etcd_host** Etcd connection string for Patroni defined as `host:port`. Not required when Patroni native Kubernetes support is used. The default is empty (use diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 40aca9716..4b2d2ef4a 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -21,6 +21,7 @@ data: # default_memory_request: 100Mi docker_image: registry.opensource.zalan.do/acid/spilo-11:1.6-p1 # enable_admin_role_for_users: "true" + # enable_crd_validation: "true" # enable_database_access: "true" enable_master_load_balancer: "false" # enable_pod_antiaffinity: "false" diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index 6726e9db1..2c0e9eda5 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -14,6 +14,7 @@ spec: scope: Namespaced subresources: status: {} + version: v1 validation: openAPIV3Schema: type: object @@ -262,5 +263,3 @@ spec: pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' scalyr_server_url: type: string - - version: v1 diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index 37a18e8dd..0936fc341 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -3,6 +3,7 @@ kind: OperatorConfiguration metadata: name: postgresql-operator-default-configuration configuration: + # enable_crd_validation: true etcd_host: "" docker_image: registry.opensource.zalan.do/acid/spilo-11:1.6-p1 # enable_shm_volume: true diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index 6f6db601e..4a578b324 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -14,6 +14,7 @@ spec: scope: Namespaced subresources: status: {} + version: v1 validation: openAPIV3Schema: type: object @@ -324,5 +325,3 @@ spec: type: string subPath: type: string - - version: v1 diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index 76d842d15..2079ed562 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -108,470 +108,472 @@ var min1 = 1.0 var minDisable = -1.0 // PostgresCRDResourceValidation to check applied manifest parameters -var PostgresCRDResourceValidation = apiextv1beta1.JSONSchemaProps{ - Type: "object", - Required: []string{"kind", "apiVersion", "spec"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "kind": { - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"postgresql"`), +var PostgresCRDResourceValidation = apiextv1beta1.CustomResourceValidation{ + OpenAPIV3Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "object", + Required: []string{"kind", "apiVersion", "spec"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "kind": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"postgresql"`), + }, }, }, - }, - "apiVersion": { - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"acid.zalan.do/v1"`), + "apiVersion": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"acid.zalan.do/v1"`), + }, }, }, - }, - "spec": { - Type: "object", - Required: []string{"numberOfInstances", "teamId", "postgresql"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "allowedSourceRanges": { - Type: "array", - Nullable: true, - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - Pattern: "^(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\/(\\d|[1-2]\\d|3[0-2])$", - }, - }, - }, - "clone": { - Type: "object", - Required: []string{"cluster"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "cluster": { - Type: "string", - }, - "s3_endpoint": { - Type: "string", - }, - "s3_access_key_id": { - Type: "string", - }, - "s3_secret_access_key": { - Type: "string", - }, - "s3_force_path_style": { - Type: "string", - }, - "s3_wal_path": { - Type: "string", - }, - "timestamp": { - Type: "string", - Description: "Date-time format that specifies a timezone as an offset relative to UTC e.g. 1996-12-19T16:39:57-08:00", - Pattern: "^([0-9]+)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])[Tt]([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\\.[0-9]+)?(([Zz])|([+-]([01][0-9]|2[0-3]):[0-5][0-9]))$", - }, - "uid": { - Type: "string", - Format: "uuid", - }, - }, - }, - "databases": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - Description: "User names specified here as database owners must be declared in the users key of the spec key", - }, - }, - }, - "dockerImage": { - Type: "string", - }, - "enableLogicalBackup": { - Type: "boolean", - }, - "enableMasterLoadBalancer": { - Type: "boolean", - }, - "enableReplicaLoadBalancer": { - Type: "boolean", - }, - "enableShmVolume": { - Type: "boolean", - }, - "init_containers": { - Type: "array", - Description: "Deprecated", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Allows: true, + "spec": { + Type: "object", + Required: []string{"numberOfInstances", "teamId", "postgresql"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "allowedSourceRanges": { + Type: "array", + Nullable: true, + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + Pattern: "^(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\/(\\d|[1-2]\\d|3[0-2])$", }, }, }, - }, - "initContainers": { - Type: "array", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Allows: true, + "clone": { + Type: "object", + Required: []string{"cluster"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "cluster": { + Type: "string", + }, + "s3_endpoint": { + Type: "string", + }, + "s3_access_key_id": { + Type: "string", + }, + "s3_secret_access_key": { + Type: "string", + }, + "s3_force_path_style": { + Type: "string", + }, + "s3_wal_path": { + Type: "string", + }, + "timestamp": { + Type: "string", + Description: "Date-time format that specifies a timezone as an offset relative to UTC e.g. 1996-12-19T16:39:57-08:00", + Pattern: "^([0-9]+)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])[Tt]([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\\.[0-9]+)?(([Zz])|([+-]([01][0-9]|2[0-3]):[0-5][0-9]))$", + }, + "uid": { + Type: "string", + Format: "uuid", }, }, }, - }, - "logicalBackupSchedule": { - Type: "string", - Pattern: "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$", - }, - "maintenanceWindows": { - Type: "array", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - Pattern: "^\\ *((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\\d):([0-5]?\\d)|(2[0-3]|[01]?\\d):([0-5]?\\d))-((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\\d):([0-5]?\\d)|(2[0-3]|[01]?\\d):([0-5]?\\d))\\ *$", + "databases": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + Description: "User names specified here as database owners must be declared in the users key of the spec key", + }, }, }, - }, - "numberOfInstances": { - Type: "integer", - Minimum: &min0, - }, - "patroni": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "initdb": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", + "dockerImage": { + Type: "string", + }, + "enableLogicalBackup": { + Type: "boolean", + }, + "enableMasterLoadBalancer": { + Type: "boolean", + }, + "enableReplicaLoadBalancer": { + Type: "boolean", + }, + "enableShmVolume": { + Type: "boolean", + }, + "init_containers": { + Type: "array", + Description: "Deprecated", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Allows: true, }, }, }, - "pg_hba": { - Type: "array", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", + }, + "initContainers": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Allows: true, }, }, }, - "slots": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", + }, + "logicalBackupSchedule": { + Type: "string", + Pattern: "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$", + }, + "maintenanceWindows": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + Pattern: "^\\ *((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\\d):([0-5]?\\d)|(2[0-3]|[01]?\\d):([0-5]?\\d))-((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\\d):([0-5]?\\d)|(2[0-3]|[01]?\\d):([0-5]?\\d))\\ *$", + }, + }, + }, + "numberOfInstances": { + Type: "integer", + Minimum: &min0, + }, + "patroni": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "initdb": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + "pg_hba": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + "slots": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, }, }, }, }, - }, - "ttl": { - Type: "integer", - }, - "loop_wait": { - Type: "integer", - }, - "retry_timeout": { - Type: "integer", - }, - "maximum_lag_on_failover": { - Type: "integer", - }, - }, - }, - "podAnnotations": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - }, - }, - }, - "pod_priority_class_name": { - Type: "string", - Description: "Deprecated", - }, - "podPriorityClassName": { - Type: "string", - }, - "postgresql": { - Type: "object", - Required: []string{"version"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "version": { - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"9.3"`), - }, - { - Raw: []byte(`"9.4"`), - }, - { - Raw: []byte(`"9.5"`), - }, - { - Raw: []byte(`"9.6"`), - }, - { - Raw: []byte(`"10"`), - }, - { - Raw: []byte(`"11"`), - }, - { - Raw: []byte(`"12"`), - }, + "ttl": { + Type: "integer", }, - }, - "parameters": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - }, + "loop_wait": { + Type: "integer", + }, + "retry_timeout": { + Type: "integer", + }, + "maximum_lag_on_failover": { + Type: "integer", }, }, }, - }, - "replicaLoadBalancer": { - Type: "boolean", - Description: "Deprecated", - }, - "resources": { - Type: "object", - Required: []string{"requests", "limits"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "limits": { - Type: "object", - Required: []string{"cpu", "memory"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "cpu": { - Type: "string", - Description: "Decimal natural followed by m, or decimal natural followed by dot followed by up to three decimal digits (precision used by Kubernetes). Must be greater than 0", - Pattern: "^(\\d+m|\\d+\\.\\d{1,3})$", - }, - "memory": { - Type: "string", - Description: "Plain integer or fixed-point integer using one of these suffixes: E, P, T, G, M, k (with or without a tailing i). Must be greater than 0", - Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", - }, - }, - }, - "requests": { - Type: "object", - Required: []string{"cpu", "memory"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "cpu": { - Type: "string", - Description: "Decimal natural followed by m, or decimal natural followed by dot followed by up to three decimal digits (precision used by Kubernetes). Must be greater than 0", - Pattern: "^(\\d+m|\\d+\\.\\d{1,3})$", - }, - "memory": { - Type: "string", - Description: "Plain integer or fixed-point integer using one of these suffixes: E, P, T, G, M, k (with or without a tailing i). Must be greater than 0", - Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", - }, + "podAnnotations": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", }, }, }, - }, - "sidecars": { - Type: "array", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Allows: true, - }, - }, + "pod_priority_class_name": { + Type: "string", + Description: "Deprecated", }, - }, - "spiloFSGroup": { - Type: "integer", - }, - "standby": { - Type: "object", - Required: []string{"s3_wal_path"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "s3_wal_path": { - Type: "string", - }, + "podPriorityClassName": { + Type: "string", }, - }, - "teamId": { - Type: "string", - }, - "tolerations": { - Type: "array", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "object", - Required: []string{"key", "operator", "effect"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "key": { - Type: "string", - }, - "operator": { - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"Equal"`), - }, - { - Raw: []byte(`"Exists"`), - }, + "postgresql": { + Type: "object", + Required: []string{"version"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "version": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"9.3"`), + }, + { + Raw: []byte(`"9.4"`), + }, + { + Raw: []byte(`"9.5"`), + }, + { + Raw: []byte(`"9.6"`), + }, + { + Raw: []byte(`"10"`), + }, + { + Raw: []byte(`"11"`), + }, + { + Raw: []byte(`"12"`), }, }, - "value": { - Type: "string", - }, - "effect": { - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"NoExecute"`), - }, - { - Raw: []byte(`"NoSchedule"`), - }, - { - Raw: []byte(`"PreferNoSchedule"`), - }, + }, + "parameters": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", }, }, - "tolerationSeconds": { - Type: "integer", - }, }, }, }, - }, - "useLoadBalancer": { - Type: "boolean", - Description: "Deprecated", - }, - "users": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "array", - Description: "Role flags specified here must not contradict each other", - Nullable: true, - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"bypassrls"`), + "replicaLoadBalancer": { + Type: "boolean", + Description: "Deprecated", + }, + "resources": { + Type: "object", + Required: []string{"requests", "limits"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "limits": { + Type: "object", + Required: []string{"cpu", "memory"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "cpu": { + Type: "string", + Description: "Decimal natural followed by m, or decimal natural followed by dot followed by up to three decimal digits (precision used by Kubernetes). Must be greater than 0", + Pattern: "^(\\d+m|\\d+\\.\\d{1,3})$", + }, + "memory": { + Type: "string", + Description: "Plain integer or fixed-point integer using one of these suffixes: E, P, T, G, M, k (with or without a tailing i). Must be greater than 0", + Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", + }, + }, + }, + "requests": { + Type: "object", + Required: []string{"cpu", "memory"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "cpu": { + Type: "string", + Description: "Decimal natural followed by m, or decimal natural followed by dot followed by up to three decimal digits (precision used by Kubernetes). Must be greater than 0", + Pattern: "^(\\d+m|\\d+\\.\\d{1,3})$", + }, + "memory": { + Type: "string", + Description: "Plain integer or fixed-point integer using one of these suffixes: E, P, T, G, M, k (with or without a tailing i). Must be greater than 0", + Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", + }, + }, + }, + }, + }, + "sidecars": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Allows: true, + }, + }, + }, + }, + "spiloFSGroup": { + Type: "integer", + }, + "standby": { + Type: "object", + Required: []string{"s3_wal_path"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "s3_wal_path": { + Type: "string", + }, + }, + }, + "teamId": { + Type: "string", + }, + "tolerations": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "object", + Required: []string{"key", "operator", "effect"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "key": { + Type: "string", + }, + "operator": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"Equal"`), + }, + { + Raw: []byte(`"Exists"`), + }, }, - { - Raw: []byte(`"BYPASSRLS"`), + }, + "value": { + Type: "string", + }, + "effect": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"NoExecute"`), + }, + { + Raw: []byte(`"NoSchedule"`), + }, + { + Raw: []byte(`"PreferNoSchedule"`), + }, }, - { - Raw: []byte(`"nobypassrls"`), - }, - { - Raw: []byte(`"NOBYPASSRLS"`), - }, - { - Raw: []byte(`"createdb"`), - }, - { - Raw: []byte(`"CREATEDB"`), - }, - { - Raw: []byte(`"nocreatedb"`), - }, - { - Raw: []byte(`"NOCREATEDB"`), - }, - { - Raw: []byte(`"createrole"`), - }, - { - Raw: []byte(`"CREATEROLE"`), - }, - { - Raw: []byte(`"nocreaterole"`), - }, - { - Raw: []byte(`"NOCREATEROLE"`), - }, - { - Raw: []byte(`"inherit"`), - }, - { - Raw: []byte(`"INHERIT"`), - }, - { - Raw: []byte(`"noinherit"`), - }, - { - Raw: []byte(`"NOINHERIT"`), - }, - { - Raw: []byte(`"login"`), - }, - { - Raw: []byte(`"LOGIN"`), - }, - { - Raw: []byte(`"nologin"`), - }, - { - Raw: []byte(`"NOLOGIN"`), - }, - { - Raw: []byte(`"replication"`), - }, - { - Raw: []byte(`"REPLICATION"`), - }, - { - Raw: []byte(`"noreplication"`), - }, - { - Raw: []byte(`"NOREPLICATION"`), - }, - { - Raw: []byte(`"superuser"`), - }, - { - Raw: []byte(`"SUPERUSER"`), - }, - { - Raw: []byte(`"nosuperuser"`), - }, - { - Raw: []byte(`"NOSUPERUSER"`), + }, + "tolerationSeconds": { + Type: "integer", + }, + }, + }, + }, + }, + "useLoadBalancer": { + Type: "boolean", + Description: "Deprecated", + }, + "users": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "array", + Description: "Role flags specified here must not contradict each other", + Nullable: true, + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"bypassrls"`), + }, + { + Raw: []byte(`"BYPASSRLS"`), + }, + { + Raw: []byte(`"nobypassrls"`), + }, + { + Raw: []byte(`"NOBYPASSRLS"`), + }, + { + Raw: []byte(`"createdb"`), + }, + { + Raw: []byte(`"CREATEDB"`), + }, + { + Raw: []byte(`"nocreatedb"`), + }, + { + Raw: []byte(`"NOCREATEDB"`), + }, + { + Raw: []byte(`"createrole"`), + }, + { + Raw: []byte(`"CREATEROLE"`), + }, + { + Raw: []byte(`"nocreaterole"`), + }, + { + Raw: []byte(`"NOCREATEROLE"`), + }, + { + Raw: []byte(`"inherit"`), + }, + { + Raw: []byte(`"INHERIT"`), + }, + { + Raw: []byte(`"noinherit"`), + }, + { + Raw: []byte(`"NOINHERIT"`), + }, + { + Raw: []byte(`"login"`), + }, + { + Raw: []byte(`"LOGIN"`), + }, + { + Raw: []byte(`"nologin"`), + }, + { + Raw: []byte(`"NOLOGIN"`), + }, + { + Raw: []byte(`"replication"`), + }, + { + Raw: []byte(`"REPLICATION"`), + }, + { + Raw: []byte(`"noreplication"`), + }, + { + Raw: []byte(`"NOREPLICATION"`), + }, + { + Raw: []byte(`"superuser"`), + }, + { + Raw: []byte(`"SUPERUSER"`), + }, + { + Raw: []byte(`"nosuperuser"`), + }, + { + Raw: []byte(`"NOSUPERUSER"`), + }, }, }, }, }, }, }, - }, - "volume": { - Type: "object", - Required: []string{"size"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "size": { - Type: "string", - Description: "Value must not be zero", - Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", - }, - "storageClass": { - Type: "string", - }, - "subPath": { - Type: "string", + "volume": { + Type: "object", + Required: []string{"size"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "size": { + Type: "string", + Description: "Value must not be zero", + Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", + }, + "storageClass": { + Type: "string", + }, + "subPath": { + Type: "string", + }, }, }, }, @@ -581,394 +583,396 @@ var PostgresCRDResourceValidation = apiextv1beta1.JSONSchemaProps{ } // OperatorConfigCRDResourceValidation to check applied manifest parameters -var OperatorConfigCRDResourceValidation = apiextv1beta1.JSONSchemaProps{ - Type: "object", - Required: []string{"kind", "apiVersion", "configuration"}, - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "kind": { - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"OperatorConfiguration"`), +var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation{ + OpenAPIV3Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "object", + Required: []string{"kind", "apiVersion", "configuration"}, + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "kind": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"OperatorConfiguration"`), + }, }, }, - }, - "apiVersion": { - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"acid.zalan.do/v1"`), + "apiVersion": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"acid.zalan.do/v1"`), + }, }, }, - }, - "configuration": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "etcd_host": { - Type: "string", - }, - "docker_image": { - Type: "string", - }, - "max_instances": { - Type: "integer", - Description: "-1 = disabled", - Minimum: &minDisable, - }, - "min_instances": { - Type: "integer", - Description: "-1 = disabled", - Minimum: &minDisable, - }, - "resync_period": { - Type: "string", - }, - "repair_period": { - Type: "string", - }, - "set_memory_request_to_limit": { - Type: "boolean", - }, - "sidecar_docker_images": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - }, + "configuration": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "etcd_host": { + Type: "string", }, - }, - "workers": { - Type: "integer", - Minimum: &min1, - }, - "users": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "replication_username": { - Type: "string", - }, - "super_username": { - Type: "string", - }, + "docker_image": { + Type: "string", }, - }, - "kubernetes": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "cluster_domain": { - Type: "string", - }, - "cluster_labels": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - }, + "max_instances": { + Type: "integer", + Description: "-1 = disabled", + Minimum: &minDisable, + }, + "min_instances": { + Type: "integer", + Description: "-1 = disabled", + Minimum: &minDisable, + }, + "resync_period": { + Type: "string", + }, + "repair_period": { + Type: "string", + }, + "set_memory_request_to_limit": { + Type: "boolean", + }, + "sidecar_docker_images": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", }, }, - "cluster_name_label": { - Type: "string", - }, - "custom_pod_annotations": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - }, + }, + "workers": { + Type: "integer", + Minimum: &min1, + }, + "users": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "replication_username": { + Type: "string", + }, + "super_username": { + Type: "string", }, }, - "enable_pod_antiaffinity": { - Type: "boolean", - }, - "enable_pod_disruption_budget": { - Type: "boolean", - }, - "infrastructure_roles_secret_name": { - Type: "string", - }, - "inherited_labels": { - Type: "array", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", + }, + "kubernetes": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "cluster_domain": { + Type: "string", + }, + "cluster_labels": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, }, }, - }, - "node_readiness_label": { - Type: "array", - Nullable: true, - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", + "cluster_name_label": { + Type: "string", + }, + "custom_pod_annotations": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, }, }, - }, - "oauth_token_secret_name": { - Type: "string", - }, - "pdb_name_format": { - Type: "string", - }, - "pod_antiaffinity_topology_key": { - Type: "string", - }, - "pod_environment_configmap": { - Type: "string", - }, - "pod_management_policy": { - Type: "string", - Enum: []apiextv1beta1.JSON{ - { - Raw: []byte(`"ordered_ready"`), - }, - { - Raw: []byte(`"parallel"`), + "enable_pod_antiaffinity": { + Type: "boolean", + }, + "enable_pod_disruption_budget": { + Type: "boolean", + }, + "infrastructure_roles_secret_name": { + Type: "string", + }, + "inherited_labels": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, }, }, - }, - "pod_role_label": { - Type: "string", - }, - "pod_service_account_name": { - Type: "string", - }, - "pod_terminate_grace_period": { - Type: "string", - }, - "secret_name_template": { - Type: "string", - }, - "spilo_fsgroup": { - Type: "integer", - }, - "spilo_privileged": { - Type: "boolean", - }, - "toleration": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", + "node_readiness_label": { + Type: "array", + Nullable: true, + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, }, }, - }, - "watched_namespace": { - Type: "string", - }, - }, - }, - "postgres_pod_resources": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "default_cpu_limit": { - Type: "string", - Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", - }, - "default_cpu_request": { - Type: "string", - Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", - }, - "default_memory_limit": { - Type: "string", - Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", - }, - "default_memory_request": { - Type: "string", - Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", - }, - }, - }, - "timeouts": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "pod_label_wait_timeout": { - Type: "string", - }, - "pod_deletion_wait_timeout": { - Type: "string", - }, - "ready_wait_interval": { - Type: "string", - }, - "ready_wait_timeout": { - Type: "string", - }, - "resource_check_interval": { - Type: "string", - }, - "resource_check_timeout": { - Type: "string", - }, - }, - }, - "load_balancer": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "db_hosted_zone": { - Type: "string", - }, - "enable_master_load_balancer": { - Type: "boolean", - }, - "enable_replica_load_balancer": { - Type: "boolean", - }, - "custom_service_annotations": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", + "oauth_token_secret_name": { + Type: "string", + }, + "pdb_name_format": { + Type: "string", + }, + "pod_antiaffinity_topology_key": { + Type: "string", + }, + "pod_environment_configmap": { + Type: "string", + }, + "pod_management_policy": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"ordered_ready"`), + }, + { + Raw: []byte(`"parallel"`), + }, }, }, - }, - "master_dns_name_format": { - Type: "string", - }, - "replica_dns_name_format": { - Type: "string", - }, - }, - }, - "aws_or_gcp": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "additional_secret_mount": { - Type: "string", - }, - "additional_secret_mount_path": { - Type: "string", - }, - "aws_region": { - Type: "string", - }, - "kube_iam_role": { - Type: "string", - }, - "log_s3_bucket": { - Type: "string", - }, - "wal_s3_bucket": { - Type: "string", - }, - }, - }, - "logical_backup": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "logical_backup_schedule": { - Type: "string", - Pattern: "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$", - }, - "logical_backup_docker_image": { - Type: "string", - }, - "logical_backup_s3_bucket": { - Type: "string", - }, - }, - }, - "debug": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "debug_logging": { - Type: "boolean", - }, - "enable_database_access": { - Type: "boolean", - }, - }, - }, - "teams_api": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "enable_admin_role_for_users": { - Type: "boolean", - }, - "enable_team_superuser": { - Type: "boolean", - }, - "enable_teams_api": { - Type: "boolean", - }, - "pam_configuration": { - Type: "string", - }, - "pam_role_name": { - Type: "string", - }, - "postgres_superuser_teams": { - Type: "array", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", + "pod_role_label": { + Type: "string", + }, + "pod_service_account_name": { + Type: "string", + }, + "pod_terminate_grace_period": { + Type: "string", + }, + "secret_name_template": { + Type: "string", + }, + "spilo_fsgroup": { + Type: "integer", + }, + "spilo_privileged": { + Type: "boolean", + }, + "toleration": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, }, }, - }, - "protected_role_names": { - Type: "array", - Items: &apiextv1beta1.JSONSchemaPropsOrArray{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - }, + "watched_namespace": { + Type: "string", }, }, - "team_admin_role": { - Type: "string", - }, - "team_api_role_configuration": { - Type: "object", - AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ - Schema: &apiextv1beta1.JSONSchemaProps{ - Type: "string", - }, + }, + "postgres_pod_resources": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "default_cpu_limit": { + Type: "string", + Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", + }, + "default_cpu_request": { + Type: "string", + Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", + }, + "default_memory_limit": { + Type: "string", + Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", + }, + "default_memory_request": { + Type: "string", + Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", }, }, - "teams_api_url": { - Type: "string", + }, + "timeouts": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "pod_label_wait_timeout": { + Type: "string", + }, + "pod_deletion_wait_timeout": { + Type: "string", + }, + "ready_wait_interval": { + Type: "string", + }, + "ready_wait_timeout": { + Type: "string", + }, + "resource_check_interval": { + Type: "string", + }, + "resource_check_timeout": { + Type: "string", + }, }, }, - }, - "logging_rest_api": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "api_port": { - Type: "integer", - }, - "cluster_history_entries": { - Type: "integer", - }, - "ring_log_lines": { - Type: "integer", + "load_balancer": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "db_hosted_zone": { + Type: "string", + }, + "enable_master_load_balancer": { + Type: "boolean", + }, + "enable_replica_load_balancer": { + Type: "boolean", + }, + "custom_service_annotations": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + "master_dns_name_format": { + Type: "string", + }, + "replica_dns_name_format": { + Type: "string", + }, }, }, - }, - "scalyr": { - Type: "object", - Properties: map[string]apiextv1beta1.JSONSchemaProps{ - "scalyr_api_key": { - Type: "string", + "aws_or_gcp": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "additional_secret_mount": { + Type: "string", + }, + "additional_secret_mount_path": { + Type: "string", + }, + "aws_region": { + Type: "string", + }, + "kube_iam_role": { + Type: "string", + }, + "log_s3_bucket": { + Type: "string", + }, + "wal_s3_bucket": { + Type: "string", + }, }, - "scalyr_cpu_limit": { - Type: "string", - Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", + }, + "logical_backup": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "logical_backup_schedule": { + Type: "string", + Pattern: "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$", + }, + "logical_backup_docker_image": { + Type: "string", + }, + "logical_backup_s3_bucket": { + Type: "string", + }, }, - "scalyr_cpu_request": { - Type: "string", - Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", + }, + "debug": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "debug_logging": { + Type: "boolean", + }, + "enable_database_access": { + Type: "boolean", + }, }, - "scalyr_image": { - Type: "string", + }, + "teams_api": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "enable_admin_role_for_users": { + Type: "boolean", + }, + "enable_team_superuser": { + Type: "boolean", + }, + "enable_teams_api": { + Type: "boolean", + }, + "pam_configuration": { + Type: "string", + }, + "pam_role_name": { + Type: "string", + }, + "postgres_superuser_teams": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + "protected_role_names": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + "team_admin_role": { + Type: "string", + }, + "team_api_role_configuration": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + "teams_api_url": { + Type: "string", + }, }, - "scalyr_memory_limit": { - Type: "string", - Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", + }, + "logging_rest_api": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "api_port": { + Type: "integer", + }, + "cluster_history_entries": { + Type: "integer", + }, + "ring_log_lines": { + Type: "integer", + }, }, - "scalyr_memory_request": { - Type: "string", - Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", - }, - "scalyr_server_url": { - Type: "string", + }, + "scalyr": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "scalyr_api_key": { + Type: "string", + }, + "scalyr_cpu_limit": { + Type: "string", + Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", + }, + "scalyr_cpu_request": { + Type: "string", + Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", + }, + "scalyr_image": { + Type: "string", + }, + "scalyr_memory_limit": { + Type: "string", + Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", + }, + "scalyr_memory_request": { + Type: "string", + Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", + }, + "scalyr_server_url": { + Type: "string", + }, }, }, }, @@ -977,7 +981,7 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.JSONSchemaProps{ }, } -func buildCRD(name, kind, plural, short string, columns []apiextv1beta1.CustomResourceColumnDefinition, validationSchema apiextv1beta1.JSONSchemaProps) *apiextv1beta1.CustomResourceDefinition { +func buildCRD(name, kind, plural, short string, columns []apiextv1beta1.CustomResourceColumnDefinition, validation apiextv1beta1.CustomResourceValidation) *apiextv1beta1.CustomResourceDefinition { return &apiextv1beta1.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -995,29 +999,39 @@ func buildCRD(name, kind, plural, short string, columns []apiextv1beta1.CustomRe Status: &apiextv1beta1.CustomResourceSubresourceStatus{}, }, AdditionalPrinterColumns: columns, - Validation: &apiextv1beta1.CustomResourceValidation{ - OpenAPIV3Schema: &validationSchema, - }, + Validation: &validation, }, } } // PostgresCRD returns CustomResourceDefinition built from PostgresCRDResource -func PostgresCRD() *apiextv1beta1.CustomResourceDefinition { +func PostgresCRD(enableValidation *bool) *apiextv1beta1.CustomResourceDefinition { + postgresCRDvalidation := apiextv1beta1.CustomResourceValidation{} + + if enableValidation != nil && *enableValidation { + postgresCRDvalidation = PostgresCRDResourceValidation + } + return buildCRD(PostgresCRDResouceName, PostgresCRDResourceKind, PostgresCRDResourcePlural, PostgresCRDResourceShort, PostgresCRDResourceColumns, - PostgresCRDResourceValidation) + postgresCRDvalidation) } // ConfigurationCRD returns CustomResourceDefinition built from OperatorConfigCRDResource -func ConfigurationCRD() *apiextv1beta1.CustomResourceDefinition { +func ConfigurationCRD(enableValidation *bool) *apiextv1beta1.CustomResourceDefinition { + opconfigCRDvalidation := apiextv1beta1.CustomResourceValidation{} + + if enableValidation != nil && *enableValidation { + opconfigCRDvalidation = OperatorConfigCRDResourceValidation + } + return buildCRD(OperatorConfigCRDResourceName, OperatorConfigCRDResouceKind, OperatorConfigCRDResourcePlural, OperatorConfigCRDResourceShort, OperatorConfigCRDResourceColumns, - OperatorConfigCRDResourceValidation) + opconfigCRDvalidation) } diff --git a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go index d00d40532..d97852b2f 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -150,6 +150,7 @@ type ScalyrConfiguration struct { // OperatorConfigurationData defines the operation config type OperatorConfigurationData struct { + EnableCRDValidation *bool `json:"enable_crd_validation,omitempty"` EtcdHost string `json:"etcd_host,omitempty"` DockerImage string `json:"docker_image,omitempty"` Workers uint32 `json:"workers,omitempty"` diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 9162ce27d..9db03ceb1 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -6,7 +6,7 @@ import ( "sync" "github.com/sirupsen/logrus" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" rbacv1beta1 "k8s.io/api/rbac/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -240,7 +240,7 @@ func (c *Controller) initController() { c.initClients() if configObjectName := os.Getenv("POSTGRES_OPERATOR_CONFIGURATION_OBJECT"); configObjectName != "" { - if err := c.createConfigurationCRD(); err != nil { + if err := c.createConfigurationCRD(c.opConfig.EnableCRDValidation); err != nil { c.logger.Fatalf("could not register Operator Configuration CustomResourceDefinition: %v", err) } if cfg, err := c.readOperatorConfigurationFromCRD(spec.GetOperatorNamespace(), configObjectName); err != nil { @@ -256,7 +256,7 @@ func (c *Controller) initController() { c.modifyConfigFromEnvironment() - if err := c.createPostgresCRD(); err != nil { + if err := c.createPostgresCRD(c.opConfig.EnableCRDValidation); err != nil { c.logger.Fatalf("could not register Postgres CustomResourceDefinition: %v", err) } diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 3ea513879..9bed7ed13 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -25,6 +25,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result := &config.Config{} // general config + result.EnableCRDValidation = fromCRD.EnableCRDValidation result.EtcdHost = fromCRD.EtcdHost result.DockerImage = fromCRD.DockerImage result.Workers = fromCRD.Workers diff --git a/pkg/controller/util.go b/pkg/controller/util.go index 0adb85dbd..9b7dca063 100644 --- a/pkg/controller/util.go +++ b/pkg/controller/util.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -91,12 +91,12 @@ func (c *Controller) createOperatorCRD(crd *apiextv1beta1.CustomResourceDefiniti }) } -func (c *Controller) createPostgresCRD() error { - return c.createOperatorCRD(acidv1.PostgresCRD()) +func (c *Controller) createPostgresCRD(enableValidation *bool) error { + return c.createOperatorCRD(acidv1.PostgresCRD(enableValidation)) } -func (c *Controller) createConfigurationCRD() error { - return c.createOperatorCRD(acidv1.ConfigurationCRD()) +func (c *Controller) createConfigurationCRD(enableValidation *bool) error { + return c.createOperatorCRD(acidv1.ConfigurationCRD(enableValidation)) } func readDecodedRole(s string) (*spec.PgUser, error) { diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index e8de85e20..52a0c4020 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -12,10 +12,11 @@ import ( // 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"` + 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"` + EnableCRDValidation *bool `name:"enable_crd_validation" default:"true"` } // Resources describes kubernetes resource specific configuration parameters