From 535517cd1b0cef2c307eb1592fc8e17fad918f34 Mon Sep 17 00:00:00 2001 From: Thomas Runyon Date: Mon, 11 Nov 2019 04:45:35 -0500 Subject: [PATCH 01/21] Custom annotations 329 (#657) * Add ability for custom annotations to database pods --- charts/postgres-operator/values-crd.yaml | 4 +- charts/postgres-operator/values.yaml | 5 +- docs/reference/cluster_manifest.md | 5 ++ docs/reference/operator_parameters.md | 5 ++ manifests/complete-postgres-manifest.yaml | 3 +- manifests/configmap.yaml | 10 ++-- ...gresql-operator-default-configuration.yaml | 3 + .../v1/operator_configuration_type.go | 1 + pkg/apis/acid.zalan.do/v1/postgresql_type.go | 1 + pkg/apis/acid.zalan.do/v1/util_test.go | 29 ++++++++++ .../acid.zalan.do/v1/zz_generated.deepcopy.go | 14 +++++ pkg/cluster/cluster_test.go | 56 ++++++++++++++++++- pkg/cluster/k8sres.go | 35 +++++++++++- pkg/controller/operator_config.go | 1 + pkg/util/config/config.go | 1 + 15 files changed, 160 insertions(+), 13 deletions(-) diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index 2728b245c..e1ed381cc 100644 --- a/charts/postgres-operator/values-crd.yaml +++ b/charts/postgres-operator/values-crd.yaml @@ -53,9 +53,11 @@ configKubernetes: cluster_domain: cluster.local # additional labels assigned to the cluster objects cluster_labels: - application: spilo + application: spilo # label assigned to Kubernetes objects created by the operator cluster_name_label: cluster-name + # additional annotations to add to every database pod + custom_pod_annotations: # toggles pod anti affinity on the Postgres pods enable_pod_antiaffinity: false # toggles PDB to set to MinAvailabe 0 or 1 diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index a14c8ab92..2af14984b 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -54,6 +54,8 @@ configKubernetes: cluster_labels: application:spilo # label assigned to Kubernetes objects created by the operator cluster_name_label: version + # annotations attached to each database pod + # custom_pod_annotations: keya:valuea # toggles pod anti affinity on the Postgres pods enable_pod_antiaffinity: "false" # toggles PDB to set to MinAvailabe 0 or 1 @@ -127,8 +129,7 @@ configLoadBalancer: # DNS zone for cluster DNS name when load balancer is configured for cluster db_hosted_zone: db.example.com # annotations to apply to service when load balancing is enabled - # custom_service_annotations: - # "keyx:valuez,keya:valuea" + # custom_service_annotations: "keyx:valuez,keya:valuea" # toggles service type load balancer pointing to the master pod of the cluster enable_master_load_balancer: "true" diff --git a/docs/reference/cluster_manifest.md b/docs/reference/cluster_manifest.md index edaada9b4..cf522d73d 100644 --- a/docs/reference/cluster_manifest.md +++ b/docs/reference/cluster_manifest.md @@ -118,6 +118,11 @@ These parameters are grouped directly under the `spec` key in the manifest. then the default priority class is taken. The priority class itself must be defined in advance. Optional. +* **podAnnotations** + A map of key value pairs that gets attached as [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) + to each pod created for the database. + + * **enableShmVolume** Start a database pod without limitations on shm memory. By default docker limit `/dev/shm` to `64M` (see e.g. the [docker diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index 41e62cc7f..9e43919fd 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -168,6 +168,11 @@ configuration they are grouped under the `kubernetes` key. Postgres pods are [terminated forcefully](https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods) after this timeout. The default is `5m`. +* **custom_pod_annotations** + This key/value map provides a list of annotations that get attached to each pod + of a database created by the operator. If the annotation key is also provided + by the database definition, the database definition value is used. + * **watched_namespace** The operator watches for Postgres objects in the given namespace. If not specified, the value is taken from the operator namespace. A special `*` diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index d1bd471db..402d007e6 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -25,7 +25,8 @@ spec: - 127.0.0.1/32 databases: foo: zalando - +# podAnnotations: +# annotation.key: value # Expert section enableShmVolume: true diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index f9223f3fe..879223a57 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -11,8 +11,8 @@ data: cluster_history_entries: "1000" cluster_labels: application:spilo cluster_name_label: version - # custom_service_annotations: - # "keyx:valuez,keya:valuea" + # custom_service_annotations: "keyx:valuez,keya:valuea" + # custom_pod_annotations: "keya:valuea" db_hosted_zone: db.example.com debug_logging: "true" # default_cpu_limit: "3" @@ -37,7 +37,7 @@ data: # logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" # logical_backup_s3_bucket: "my-bucket-url" # logical_backup_schedule: "30 00 * * *" - master_dns_name_format: '{cluster}.{team}.staging.{hostedzone}' + master_dns_name_format: "{cluster}.{team}.staging.{hostedzone}" # master_pod_move_timeout: 10m # max_instances: "-1" # min_instances: "-1" @@ -60,13 +60,13 @@ data: ready_wait_interval: 3s ready_wait_timeout: 30s repair_period: 5m - replica_dns_name_format: '{cluster}-repl.{team}.staging.{hostedzone}' + replica_dns_name_format: "{cluster}-repl.{team}.staging.{hostedzone}" replication_username: standby resource_check_interval: 3s resource_check_timeout: 10m resync_period: 5m ring_log_lines: "100" - secret_name_template: '{username}.{cluster}.credentials' + secret_name_template: "{username}.{cluster}.credentials" # sidecar_docker_images: "" # set_memory_request_to_limit: "false" spilo_privileged: "false" diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index ad4d028c3..e1ecd1038 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -22,6 +22,9 @@ configuration: cluster_labels: application: spilo cluster_name_label: cluster-name + # custom_pod_annotations: + # keya: valuea + # keyb: valueb enable_pod_antiaffinity: false enable_pod_disruption_budget: true # infrastructure_roles_secret_name: "" 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 02648b83b..6adfb778e 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -59,6 +59,7 @@ type KubernetesMetaConfiguration struct { InheritedLabels []string `json:"inherited_labels,omitempty"` ClusterNameLabel string `json:"cluster_name_label,omitempty"` NodeReadinessLabel map[string]string `json:"node_readiness_label,omitempty"` + CustomPodAnnotations map[string]string `json:"custom_pod_annotations,omitempty"` // TODO: use a proper toleration structure? PodToleration map[string]string `json:"toleration,omitempty"` // TODO: use namespacedname diff --git a/pkg/apis/acid.zalan.do/v1/postgresql_type.go b/pkg/apis/acid.zalan.do/v1/postgresql_type.go index 72e40e122..515a73ff0 100644 --- a/pkg/apis/acid.zalan.do/v1/postgresql_type.go +++ b/pkg/apis/acid.zalan.do/v1/postgresql_type.go @@ -59,6 +59,7 @@ type PostgresSpec struct { EnableLogicalBackup bool `json:"enableLogicalBackup,omitempty"` LogicalBackupSchedule string `json:"logicalBackupSchedule,omitempty"` StandbyCluster *StandbyDescription `json:"standby"` + PodAnnotations map[string]string `json:"podAnnotations"` // deprecated json tags InitContainersOld []v1.Container `json:"init_containers,omitempty"` diff --git a/pkg/apis/acid.zalan.do/v1/util_test.go b/pkg/apis/acid.zalan.do/v1/util_test.go index 6c1b63ece..cf3b080a5 100644 --- a/pkg/apis/acid.zalan.do/v1/util_test.go +++ b/pkg/apis/acid.zalan.do/v1/util_test.go @@ -437,6 +437,16 @@ var postgresqlList = []struct { PostgresqlList{}, errors.New("unexpected end of JSON input")}} +var annotations = []struct { + in []byte + annotations map[string]string + err error +}{{ + in: []byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1","metadata": {"name": "acid-testcluster1"}, "spec": {"podAnnotations": {"foo": "bar"},"teamId": "acid", "clone": {"cluster": "team-batman"}}}`), + annotations: map[string]string{"foo": "bar"}, + err: nil}, +} + func mustParseTime(s string) metav1.Time { v, err := time.Parse("15:04", s) if err != nil { @@ -482,6 +492,25 @@ func TestWeekdayTime(t *testing.T) { } } +func TestClusterAnnotations(t *testing.T) { + for _, tt := range annotations { + var cluster Postgresql + err := cluster.UnmarshalJSON(tt.in) + if err != nil { + if tt.err == nil || err.Error() != tt.err.Error() { + t.Errorf("Unable to marshal cluster with annotations: expected %v got %v", tt.err, err) + } + continue + } + for k, v := range cluster.Spec.PodAnnotations { + found, expected := v, tt.annotations[k] + if found != expected { + t.Errorf("Didn't find correct value for key %v in for podAnnotations: Expected %v found %v", k, expected, found) + } + } + } +} + func TestClusterName(t *testing.T) { for _, tt := range clusterNames { name, err := extractClusterName(tt.in, tt.inTeam) diff --git a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go index 8e3411219..793f236a5 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -102,6 +102,13 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura (*out)[key] = val } } + if in.CustomPodAnnotations != nil { + in, out := &in.CustomPodAnnotations, &out.CustomPodAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.PodToleration != nil { in, out := &in.PodToleration, &out.PodToleration *out = make(map[string]string, len(*in)) @@ -513,6 +520,13 @@ func (in *PostgresSpec) DeepCopyInto(out *PostgresSpec) { *out = new(StandbyDescription) **out = **in } + if in.PodAnnotations != nil { + in, out := &in.PodAnnotations, &out.PodAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.InitContainersOld != nil { in, out := &in.InitContainersOld, &out.InitContainersOld *out = make([]corev1.Container, len(*in)) diff --git a/pkg/cluster/cluster_test.go b/pkg/cluster/cluster_test.go index 6f10aae22..85d014d8a 100644 --- a/pkg/cluster/cluster_test.go +++ b/pkg/cluster/cluster_test.go @@ -11,7 +11,7 @@ import ( "github.com/zalando/postgres-operator/pkg/util/config" "github.com/zalando/postgres-operator/pkg/util/k8sutil" "github.com/zalando/postgres-operator/pkg/util/teams" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" ) const ( @@ -328,3 +328,57 @@ func TestShouldDeleteSecret(t *testing.T) { } } } + +func TestPodAnnotations(t *testing.T) { + testName := "TestPodAnnotations" + tests := []struct { + subTest string + operator map[string]string + database map[string]string + merged map[string]string + }{ + { + subTest: "No Annotations", + operator: make(map[string]string), + database: make(map[string]string), + merged: make(map[string]string), + }, + { + subTest: "Operator Config Annotations", + operator: map[string]string{"foo": "bar"}, + database: make(map[string]string), + merged: map[string]string{"foo": "bar"}, + }, + { + subTest: "Database Config Annotations", + operator: make(map[string]string), + database: map[string]string{"foo": "bar"}, + merged: map[string]string{"foo": "bar"}, + }, + { + subTest: "Database Config overrides Operator Config Annotations", + operator: map[string]string{"foo": "bar", "global": "foo"}, + database: map[string]string{"foo": "baz", "local": "foo"}, + merged: map[string]string{"foo": "baz", "global": "foo", "local": "foo"}, + }, + } + + for _, tt := range tests { + cl.OpConfig.CustomPodAnnotations = tt.operator + cl.Postgresql.Spec.PodAnnotations = tt.database + + annotations := cl.generatePodAnnotations(&cl.Postgresql.Spec) + for k, v := range annotations { + if observed, expected := v, tt.merged[k]; observed != expected { + t.Errorf("%v expects annotation value %v for key %v, but found %v", + testName+"/"+tt.subTest, expected, observed, k) + } + } + for k, v := range tt.merged { + if observed, expected := annotations[k], v; observed != expected { + t.Errorf("%v expects annotation value %v for key %v, but found %v", + testName+"/"+tt.subTest, expected, observed, k) + } + } + } +} diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 78d128387..ddadf8d52 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -430,6 +430,7 @@ func mountShmVolumeNeeded(opConfig config.Config, pgSpec *acidv1.PostgresSpec) * func generatePodTemplate( namespace string, labels labels.Set, + annotations map[string]string, spiloContainer *v1.Container, initContainers []v1.Container, sidecarContainers []v1.Container, @@ -485,13 +486,17 @@ func generatePodTemplate( template := v1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - Namespace: namespace, + Labels: labels, + Namespace: namespace, + Annotations: annotations, }, Spec: podSpec, } if kubeIAMRole != "" { - template.Annotations = map[string]string{constants.KubeIAmAnnotation: kubeIAMRole} + if template.Annotations == nil{ + template.Annotations = make(map[string]string) + } + template.Annotations[constants.KubeIAmAnnotation] = kubeIAMRole } return &template, nil @@ -881,10 +886,13 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef effectiveFSGroup = spec.SpiloFSGroup } + annotations := c.generatePodAnnotations(spec) + // generate pod template for the statefulset, based on the spilo container and sidecars if podTemplate, err = generatePodTemplate( c.Namespace, c.labelsSet(true), + annotations, spiloContainer, spec.InitContainers, sidecarContainers, @@ -949,6 +957,24 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef return statefulSet, nil } +func (c *Cluster) generatePodAnnotations(spec *acidv1.PostgresSpec) map[string]string { + annotations := make(map[string]string) + for k, v := range c.OpConfig.CustomPodAnnotations { + annotations[k] = v + } + if spec != nil || spec.PodAnnotations != nil { + for k, v := range spec.PodAnnotations { + annotations[k] = v + } + } + + if len(annotations) == 0 { + return nil + } + + return annotations +} + func generateScalyrSidecarSpec(clusterName, APIKey, serverURL, dockerImage string, containerResources *acidv1.Resources, logger *logrus.Entry) *acidv1.Sidecar { if APIKey == "" || dockerImage == "" { @@ -1462,10 +1488,13 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1beta1.CronJob, error) { }, }} + annotations := c.generatePodAnnotations(&c.Spec) + // re-use the method that generates DB pod templates if podTemplate, err = generatePodTemplate( c.Namespace, labels, + annotations, logicalBackupContainer, []v1.Container{}, []v1.Container{}, diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 9da4bbaf8..b91fd511f 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -41,6 +41,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.ReplicationUsername = fromCRD.PostgresUsersConfiguration.ReplicationUsername // kubernetes config + result.CustomPodAnnotations = fromCRD.Kubernetes.CustomPodAnnotations result.PodServiceAccountName = fromCRD.Kubernetes.PodServiceAccountName result.PodServiceAccountDefinition = fromCRD.Kubernetes.PodServiceAccountDefinition result.PodServiceAccountRoleBindingDefinition = fromCRD.Kubernetes.PodServiceAccountRoleBindingDefinition diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 5dd25d401..bdbbf0fdc 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -109,6 +109,7 @@ type Config struct { EnableMasterLoadBalancer bool `name:"enable_master_load_balancer" default:"true"` EnableReplicaLoadBalancer bool `name:"enable_replica_load_balancer" default:"false"` CustomServiceAnnotations map[string]string `name:"custom_service_annotations"` + CustomPodAnnotations map[string]string `name:"custom_pod_annotations"` EnablePodAntiAffinity bool `name:"enable_pod_antiaffinity" default:"false"` PodAntiAffinityTopologyKey string `name:"pod_antiaffinity_topology_key" default:"kubernetes.io/hostname"` // deprecated and kept for backward compatibility From de14323f8ed11f087722f7424b49faf8cfb79ca8 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Tue, 12 Nov 2019 10:57:48 +0100 Subject: [PATCH 02/21] disable load balancers by default in examples (#715) --- charts/postgres-operator/values-crd.yaml | 2 +- charts/postgres-operator/values.yaml | 2 +- manifests/complete-postgres-manifest.yaml | 4 ++-- manifests/configmap.yaml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index e1ed381cc..06a5b483f 100644 --- a/charts/postgres-operator/values-crd.yaml +++ b/charts/postgres-operator/values-crd.yaml @@ -138,7 +138,7 @@ configLoadBalancer: # keya: valuea # toggles service type load balancer pointing to the master pod of the cluster - enable_master_load_balancer: true + enable_master_load_balancer: false # toggles service type load balancer pointing to the replica pod of the cluster enable_replica_load_balancer: false # defines the DNS name string template for the master load balancer cluster diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index 2af14984b..2c499a036 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -132,7 +132,7 @@ configLoadBalancer: # custom_service_annotations: "keyx:valuez,keya:valuea" # toggles service type load balancer pointing to the master pod of the cluster - enable_master_load_balancer: "true" + enable_master_load_balancer: "false" # toggles service type load balancer pointing to the replica pod of the cluster enable_replica_load_balancer: "false" # defines the DNS name string template for the master load balancer cluster diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index 402d007e6..34dd6cf83 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -19,8 +19,8 @@ spec: zalando: - superuser - createdb - enableMasterLoadBalancer: true - enableReplicaLoadBalancer: true + enableMasterLoadBalancer: false + enableReplicaLoadBalancer: false allowedSourceRanges: # load balancers' source ranges for both master and replica services - 127.0.0.1/32 databases: diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 879223a57..c64e45cbd 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -22,7 +22,7 @@ data: docker_image: registry.opensource.zalan.do/acid/spilo-11:1.6-p1 # enable_admin_role_for_users: "true" # enable_database_access: "true" - enable_master_load_balancer: "true" + enable_master_load_balancer: "false" # enable_pod_antiaffinity: "false" # enable_pod_disruption_budget: "true" enable_replica_load_balancer: "false" From 63d1f3bbe4ec456d8025f18c5e47cb3f872ea756 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Mon, 18 Nov 2019 12:13:05 +0100 Subject: [PATCH 03/21] add get for deployments to operator RBAC (#724) --- manifests/operator-service-account-rbac.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/manifests/operator-service-account-rbac.yaml b/manifests/operator-service-account-rbac.yaml index e95fe320b..9be8c7ab9 100644 --- a/manifests/operator-service-account-rbac.yaml +++ b/manifests/operator-service-account-rbac.yaml @@ -103,6 +103,12 @@ rules: - delete - get - patch +- apiGroups: + - apps + resources: + - deployments + verbs: + - get - apiGroups: - apps resources: From 0b544ae43f2081ccd9bb1d1dc067b43473becec6 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Tue, 19 Nov 2019 18:06:55 +0100 Subject: [PATCH 04/21] pass additionalSecretMount to logical backup pod (#714) --- pkg/cluster/k8sres.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index ddadf8d52..a0d9604fd 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -493,7 +493,7 @@ func generatePodTemplate( Spec: podSpec, } if kubeIAMRole != "" { - if template.Annotations == nil{ + if template.Annotations == nil { template.Annotations = make(map[string]string) } template.Annotations[constants.KubeIAmAnnotation] = kubeIAMRole @@ -967,7 +967,7 @@ func (c *Cluster) generatePodAnnotations(spec *acidv1.PostgresSpec) map[string]s annotations[k] = v } } - + if len(annotations) == 0 { return nil } @@ -1508,8 +1508,8 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1beta1.CronJob, error) { util.False(), false, "", - "", - ""); err != nil { + c.OpConfig.AdditionalSecretMount, + c.OpConfig.AdditionalSecretMountPath); err != nil { return nil, fmt.Errorf("could not generate pod template for logical backup pod: %v", err) } From f9487e41c1cdfc27ef461fb35fe35e0df2f0e121 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Wed, 20 Nov 2019 13:58:41 +0100 Subject: [PATCH 05/21] inject cluster name label into logical backup pod (#725) * inject cluster name label into logical backup pod --- docker/logical-backup/dump.sh | 41 +++----------------- manifests/operator-service-account-rbac.yaml | 6 --- pkg/cluster/k8sres.go | 4 ++ 3 files changed, 9 insertions(+), 42 deletions(-) diff --git a/docker/logical-backup/dump.sh b/docker/logical-backup/dump.sh index c3cf5ba67..ee64bd811 100755 --- a/docker/logical-backup/dump.sh +++ b/docker/logical-backup/dump.sh @@ -14,9 +14,8 @@ PG_BIN=$PG_DIR/$PG_VERSION/bin DUMP_SIZE_COEFF=5 TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) -K8S_API_URL=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT +K8S_API_URL=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1 CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt -CLUSTER_NAME_LABEL=cluster-name function estimate_size { "$PG_BIN"/psql -tqAc "${ALL_DB_SIZE_QUERY}" @@ -49,53 +48,23 @@ function aws_upload { function get_pods { declare -r SELECTOR="$1" - curl "${K8S_API_URL}/api/v1/namespaces/${POD_NAMESPACE}/pods?$SELECTOR" \ - --cacert $CERT \ + curl "${K8S_API_URL}/namespaces/${POD_NAMESPACE}/pods?$SELECTOR" \ + --cacert $CERT \ -H "Authorization: Bearer ${TOKEN}" | jq .items[].status.podIP -r } function get_current_pod { - curl "${K8S_API_URL}/api/v1/namespaces/${POD_NAMESPACE}/pods?fieldSelector=metadata.name%3D${HOSTNAME}" \ - --cacert $CERT \ + curl "${K8S_API_URL}/namespaces/${POD_NAMESPACE}/pods?fieldSelector=metadata.name%3D${HOSTNAME}" \ + --cacert $CERT \ -H "Authorization: Bearer ${TOKEN}" } declare -a search_strategy=( - get_cluster_name_label list_all_replica_pods_current_node list_all_replica_pods_any_node get_master_pod ) -function get_config_resource() { - curl "${K8S_API_URL}/apis/apps/v1/namespaces/default/deployments/postgres-operator" \ - --cacert $CERT \ - -H "Authorization: Bearer ${TOKEN}" | jq '.spec.template.spec.containers[0].env[] | select(.name == "$1") | .value' -} - -function get_cluster_name_label { - local config - local clustername - - config=$(get_config_resource "CONFIG_MAP_NAME") - if [ -n "$config" ]; then - clustername=$(curl "${K8S_API_URL}/api/v1/namespaces/default/configmaps/${config}" \ - --cacert $CERT \ - -H "Authorization: Bearer ${TOKEN}" | jq '.data.cluster_name_label') - else - config=$(get_config_resource "POSTGRES_OPERATOR_CONFIGURATION_OBJECT") - if [ -n "$config" ]; then - clustername=$(curl "${K8S_API_URL}/apis/acid.zalan.do/v1/namespaces/default/operatorconfigurations/${config}" \ - --cacert $CERT \ - -H "Authorization: Bearer ${TOKEN}" | jq '.configuration.kubernetes.cluster_name_label') - fi - fi - - if [ -n "$clustername" ]; then - CLUSTER_NAME_LABEL=${clustername} - fi; -} - function list_all_replica_pods_current_node { get_pods "labelSelector=${CLUSTER_NAME_LABEL}%3D${SCOPE},spilo-role%3Dreplica&fieldSelector=spec.nodeName%3D${CURRENT_NODENAME}" | head -n 1 } diff --git a/manifests/operator-service-account-rbac.yaml b/manifests/operator-service-account-rbac.yaml index 9be8c7ab9..e95fe320b 100644 --- a/manifests/operator-service-account-rbac.yaml +++ b/manifests/operator-service-account-rbac.yaml @@ -103,12 +103,6 @@ rules: - delete - get - patch -- apiGroups: - - apps - resources: - - deployments - verbs: - - get - apiGroups: - apps resources: diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index a0d9604fd..d5cc4ce39 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -1557,6 +1557,10 @@ func (c *Cluster) generateLogicalBackupPodEnvVars() []v1.EnvVar { Name: "SCOPE", Value: c.Name, }, + { + Name: "CLUSTER_NAME_LABEL", + Value: c.OpConfig.ClusterNameLabel, + }, { Name: "POD_NAMESPACE", ValueFrom: &v1.EnvVarSource{ From 2ce602fcd7a472d3c586f1619efdbacdb8418d4f Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Tue, 26 Nov 2019 10:28:32 +0100 Subject: [PATCH 06/21] fix errors when changing service type (#716) * fix errors when changing service type * nullify service and endpoint before recreation * improve wait for delete logic and reuse config parameters --- pkg/cluster/resources.go | 46 +++++++++++++++++++++++++------- pkg/util/constants/kubernetes.go | 8 +++--- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/pkg/cluster/resources.go b/pkg/cluster/resources.go index 23ac3f348..3e8f73916 100644 --- a/pkg/cluster/resources.go +++ b/pkg/cluster/resources.go @@ -13,7 +13,6 @@ import ( "k8s.io/apimachinery/pkg/types" "github.com/zalando/postgres-operator/pkg/util" - "github.com/zalando/postgres-operator/pkg/util/constants" "github.com/zalando/postgres-operator/pkg/util/k8sutil" "github.com/zalando/postgres-operator/pkg/util/retryutil" ) @@ -278,7 +277,8 @@ func (c *Cluster) replaceStatefulSet(newStatefulSet *appsv1.StatefulSet) error { oldStatefulset := c.Statefulset options := metav1.DeleteOptions{PropagationPolicy: &deletePropagationPolicy} - if err := c.KubeClient.StatefulSets(oldStatefulset.Namespace).Delete(oldStatefulset.Name, &options); err != nil { + err := c.KubeClient.StatefulSets(oldStatefulset.Namespace).Delete(oldStatefulset.Name, &options) + if err != nil { return fmt.Errorf("could not delete statefulset %q: %v", statefulSetName, err) } // make sure we clear the stored statefulset status if the subsequent create fails. @@ -286,11 +286,16 @@ func (c *Cluster) replaceStatefulSet(newStatefulSet *appsv1.StatefulSet) error { // wait until the statefulset is truly deleted c.logger.Debugf("waiting for the statefulset to be deleted") - err := retryutil.Retry(constants.StatefulsetDeletionInterval, constants.StatefulsetDeletionTimeout, + err = retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout, func() (bool, error) { - _, err := c.KubeClient.StatefulSets(oldStatefulset.Namespace).Get(oldStatefulset.Name, metav1.GetOptions{}) - - return err != nil, nil + _, err2 := c.KubeClient.StatefulSets(oldStatefulset.Namespace).Get(oldStatefulset.Name, metav1.GetOptions{}) + if err2 == nil { + return false, nil + } + if k8sutil.ResourceNotFound(err2) { + return true, nil + } + return false, err2 }) if err != nil { return fmt.Errorf("could not delete statefulset: %v", err) @@ -380,13 +385,27 @@ func (c *Cluster) updateService(role PostgresRole, newService *v1.Service) error return fmt.Errorf("could not delete service %q: %v", serviceName, err) } - c.Endpoints[role] = nil - svc, err := c.KubeClient.Services(serviceName.Namespace).Create(newService) + // wait until the service is truly deleted + c.logger.Debugf("waiting for service to be deleted") + + err = retryutil.Retry(c.OpConfig.ResourceCheckInterval, c.OpConfig.ResourceCheckTimeout, + func() (bool, error) { + _, err2 := c.KubeClient.Services(serviceName.Namespace).Get(serviceName.Name, metav1.GetOptions{}) + if err2 == nil { + return false, nil + } + if k8sutil.ResourceNotFound(err2) { + return true, nil + } + return false, err2 + }) if err != nil { - return fmt.Errorf("could not create service %q: %v", serviceName, err) + return fmt.Errorf("could not delete service %q: %v", serviceName, err) } - c.Services[role] = svc + // make sure we clear the stored service and endpoint status if the subsequent create fails. + c.Services[role] = nil + c.Endpoints[role] = nil if role == Master { // create the new endpoint using the addresses obtained from the previous one endpointSpec := c.generateEndpoint(role, currentEndpoint.Subsets) @@ -398,6 +417,13 @@ func (c *Cluster) updateService(role PostgresRole, newService *v1.Service) error c.Endpoints[role] = ep } + svc, err := c.KubeClient.Services(serviceName.Namespace).Create(newService) + if err != nil { + return fmt.Errorf("could not create service %q: %v", serviceName, err) + } + + c.Services[role] = svc + return nil } diff --git a/pkg/util/constants/kubernetes.go b/pkg/util/constants/kubernetes.go index a4ea73e80..be79687eb 100644 --- a/pkg/util/constants/kubernetes.go +++ b/pkg/util/constants/kubernetes.go @@ -4,11 +4,9 @@ import "time" // General kubernetes-related constants const ( - PostgresContainerName = "postgres" - PostgresContainerIdx = 0 - K8sAPIPath = "/apis" - StatefulsetDeletionInterval = 1 * time.Second - StatefulsetDeletionTimeout = 30 * time.Second + PostgresContainerName = "postgres" + PostgresContainerIdx = 0 + K8sAPIPath = "/apis" QueueResyncPeriodPod = 5 * time.Minute QueueResyncPeriodTPR = 5 * time.Minute From 5f87384d7f1b80805e909f50ca773d46d3609321 Mon Sep 17 00:00:00 2001 From: Armin Nesiren Date: Tue, 26 Nov 2019 10:40:49 +0100 Subject: [PATCH 07/21] Passing endpoint, access and secret key to logical-backup container (#628) * Added possibility to add custom annotations to LoadBalancer service. * Added parameters for custom endpoint, access and secret key for logical backup. * Modified dump.sh so it knows how to handle new features. Configurable S3 SSE --- charts/postgres-operator/values-crd.yaml | 12 ++++++++++-- charts/postgres-operator/values.yaml | 12 ++++++++++-- docker/logical-backup/dump.sh | 12 +++++++----- docs/reference/operator_parameters.md | 13 +++++++++++++ manifests/configmap.yaml | 4 ++++ ...stgresql-operator-default-configuration.yaml | 7 ++++++- .../v1/operator_configuration_type.go | 11 ++++++++--- pkg/cluster/k8sres.go | 17 ++++++++++++++++- pkg/controller/operator_config.go | 4 ++++ pkg/util/config/config.go | 12 ++++++++---- 10 files changed, 86 insertions(+), 18 deletions(-) diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index 06a5b483f..af05ae56c 100644 --- a/charts/postgres-operator/values-crd.yaml +++ b/charts/postgres-operator/values-crd.yaml @@ -184,12 +184,20 @@ configAwsOrGcp: # configure K8s cron job managed by the operator configLogicalBackup: - # backup schedule in the cron format - logical_backup_schedule: "30 00 * * *" # image for pods of the logical backup job (example runs pg_dumpall) logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" + # S3 Access Key ID + logical_backup_s3_access_key_id: "" # S3 bucket to store backup results logical_backup_s3_bucket: "my-bucket-url" + # S3 endpoint url when not using AWS + logical_backup_s3_endpoint: "" + # S3 Secret Access Key + logical_backup_s3_secret_access_key: "" + # S3 server side encription + logical_backup_s3_sse: "AES256" + # backup schedule in the cron format + logical_backup_schedule: "30 00 * * *" # automate creation of human users with teams API service configTeamsApi: diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index 2c499a036..b572b5844 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -178,12 +178,20 @@ configAwsOrGcp: # configure K8s cron job managed by the operator configLogicalBackup: - # backup schedule in the cron format - logical_backup_schedule: "30 00 * * *" # image for pods of the logical backup job (example runs pg_dumpall) logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" + # S3 Access Key ID + logical_backup_s3_access_key_id: "" # S3 bucket to store backup results logical_backup_s3_bucket: "my-bucket-url" + # S3 endpoint url when not using AWS + logical_backup_s3_endpoint: "" + # S3 Secret Access Key + logical_backup_s3_secret_access_key: "" + # S3 server side encription + logical_backup_s3_sse: "AES256" + # backup schedule in the cron format + logical_backup_schedule: "30 00 * * *" # automate creation of human users with teams API service configTeamsApi: diff --git a/docker/logical-backup/dump.sh b/docker/logical-backup/dump.sh index ee64bd811..5c2e478a9 100755 --- a/docker/logical-backup/dump.sh +++ b/docker/logical-backup/dump.sh @@ -38,11 +38,13 @@ function aws_upload { # NB: $LOGICAL_BACKUP_S3_BUCKET_SCOPE_SUFFIX already contains the leading "/" when set by the Postgres Operator PATH_TO_BACKUP=s3://$LOGICAL_BACKUP_S3_BUCKET"/spilo/"$SCOPE$LOGICAL_BACKUP_S3_BUCKET_SCOPE_SUFFIX"/logical_backups/"$(date +%s).sql.gz - if [ -z "$EXPECTED_SIZE" ]; then - aws s3 cp - "$PATH_TO_BACKUP" --debug --sse="AES256" - else - aws s3 cp - "$PATH_TO_BACKUP" --debug --expected-size "$EXPECTED_SIZE" --sse="AES256" - fi; + args=() + + [[ ! -z "$EXPECTED_SIZE" ]] && args+=("--expected-size=$EXPECTED_SIZE") + [[ ! -z "$LOGICAL_BACKUP_S3_ENDPOINT" ]] && args+=("--endpoint-url=\"$LOGICAL_BACKUP_S3_ENDPOINT\"") + [[ ! "$LOGICAL_BACKUP_S3_SSE" == "" ]] && args+=("--sse=\"$LOGICAL_BACKUP_S3_SSE\"") + + aws s3 cp - "$PATH_TO_BACKUP" "${args[@]//\'/}" --debug } function get_pods { diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index 9e43919fd..a024aad1f 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -441,6 +441,19 @@ grouped under the `logical_backup` key. S3 bucket to store backup results. The bucket has to be present and accessible by Postgres pods. Default: empty. +* **logical_backup_s3_endpoint** + When using non-AWS S3 storage, endpoint can be set as a ENV variable. + +* **logical_backup_s3_sse** + Specify server side encription that S3 storage is using. If empty string + is specified, no argument will be passed to `aws s3` command. Default: "AES256". + +* **logical_backup_s3_access_key_id** + When set, value will be in AWS_ACCESS_KEY_ID env variable. The Default is empty. + +* **logical_backup_s3_secret_access_key** + When set, value will be in AWS_SECRET_ACCESS_KEY env variable. The Default is empty. + ## Debugging the operator Options to aid debugging of the operator itself. Grouped under the `debug` key. diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index c64e45cbd..40aca9716 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -35,7 +35,11 @@ data: # kube_iam_role: "" # log_s3_bucket: "" # logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" + # logical_backup_s3_access_key_id: "" # logical_backup_s3_bucket: "my-bucket-url" + # logical_backup_s3_endpoint: "" + # logical_backup_s3_secret_access_key: "" + # logical_backup_s3_sse: "AES256" # logical_backup_schedule: "30 00 * * *" master_dns_name_format: "{cluster}.{team}.staging.{hostedzone}" # master_pod_move_timeout: 10m diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index e1ecd1038..94f91f1f0 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -74,9 +74,14 @@ configuration: # log_s3_bucket: "" # wal_s3_bucket: "" logical_backup: - logical_backup_schedule: "30 00 * * *" + log_s3_bucket: "" logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" + logical_backup_s3_access_key_id: "" logical_backup_s3_bucket: "my-bucket-url" + logical_backup_s3_endpoint: "" + logical_backup_s3_secret_access_key: "" + logical_backup_s3_sse: "AES256" + logical_backup_schedule: "30 00 * * *" debug: debug_logging: true enable_database_access: true 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 6adfb778e..d00d40532 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -184,8 +184,13 @@ type OperatorConfigurationUsers struct { //Duration shortens this frequently used name type Duration time.Duration +// OperatorLogicalBackupConfiguration defines configration for logical backup type OperatorLogicalBackupConfiguration struct { - Schedule string `json:"logical_backup_schedule,omitempty"` - DockerImage string `json:"logical_backup_docker_image,omitempty"` - S3Bucket string `json:"logical_backup_s3_bucket,omitempty"` + Schedule string `json:"logical_backup_schedule,omitempty"` + DockerImage string `json:"logical_backup_docker_image,omitempty"` + S3Bucket string `json:"logical_backup_s3_bucket,omitempty"` + S3Endpoint string `json:"logical_backup_s3_endpoint,omitempty"` + S3AccessKeyID string `json:"logical_backup_s3_access_key_id,omitempty"` + S3SecretAccessKey string `json:"logical_backup_s3_secret_access_key,omitempty"` + S3SSE string `json:"logical_backup_s3_sse,omitempty"` } diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index d5cc4ce39..95e83454f 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -1575,6 +1575,14 @@ func (c *Cluster) generateLogicalBackupPodEnvVars() []v1.EnvVar { Name: "LOGICAL_BACKUP_S3_BUCKET", Value: c.OpConfig.LogicalBackup.LogicalBackupS3Bucket, }, + { + Name: "LOGICAL_BACKUP_S3_ENDPOINT", + Value: c.OpConfig.LogicalBackup.LogicalBackupS3Endpoint, + }, + { + Name: "LOGICAL_BACKUP_S3_SSE", + Value: c.OpConfig.LogicalBackup.LogicalBackupS3SSE, + }, { Name: "LOGICAL_BACKUP_S3_BUCKET_SCOPE_SUFFIX", Value: getBucketScopeSuffix(string(c.Postgresql.GetUID())), @@ -1613,8 +1621,15 @@ func (c *Cluster) generateLogicalBackupPodEnvVars() []v1.EnvVar { }, } - c.logger.Debugf("Generated logical backup env vars %v", envVars) + if c.OpConfig.LogicalBackup.LogicalBackupS3AccessKeyID != "" { + envVars = append(envVars, v1.EnvVar{Name: "AWS_ACCESS_KEY_ID", Value: c.OpConfig.LogicalBackup.LogicalBackupS3AccessKeyID}) + } + if c.OpConfig.LogicalBackup.LogicalBackupS3SecretAccessKey != "" { + envVars = append(envVars, v1.EnvVar{Name: "AWS_SECRET_ACCESS_KEY", Value: c.OpConfig.LogicalBackup.LogicalBackupS3SecretAccessKey}) + } + + c.logger.Debugf("Generated logical backup env vars %v", envVars) return envVars } diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index b91fd511f..3ea513879 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -101,6 +101,10 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.LogicalBackupSchedule = fromCRD.LogicalBackup.Schedule result.LogicalBackupDockerImage = fromCRD.LogicalBackup.DockerImage result.LogicalBackupS3Bucket = fromCRD.LogicalBackup.S3Bucket + result.LogicalBackupS3Endpoint = fromCRD.LogicalBackup.S3Endpoint + result.LogicalBackupS3AccessKeyID = fromCRD.LogicalBackup.S3AccessKeyID + result.LogicalBackupS3SecretAccessKey = fromCRD.LogicalBackup.S3SecretAccessKey + result.LogicalBackupS3SSE = fromCRD.LogicalBackup.S3SSE // debug config result.DebugLogging = fromCRD.OperatorDebug.DebugLogging diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index bdbbf0fdc..e8de85e20 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -68,11 +68,15 @@ type Scalyr struct { ScalyrMemoryLimit string `name:"scalyr_memory_limit" default:"1Gi"` } -// LogicalBackup +// LogicalBackup defines configration for logical backup type LogicalBackup struct { - LogicalBackupSchedule string `name:"logical_backup_schedule" default:"30 00 * * *"` - LogicalBackupDockerImage string `name:"logical_backup_docker_image" default:"registry.opensource.zalan.do/acid/logical-backup"` - LogicalBackupS3Bucket string `name:"logical_backup_s3_bucket" default:""` + LogicalBackupSchedule string `name:"logical_backup_schedule" default:"30 00 * * *"` + LogicalBackupDockerImage string `name:"logical_backup_docker_image" default:"registry.opensource.zalan.do/acid/logical-backup"` + LogicalBackupS3Bucket string `name:"logical_backup_s3_bucket" default:""` + LogicalBackupS3Endpoint string `name:"logical_backup_s3_endpoint" default:""` + LogicalBackupS3AccessKeyID string `name:"logical_backup_s3_access_key_id" default:""` + LogicalBackupS3SecretAccessKey string `name:"logical_backup_s3_secret_access_key" default:""` + LogicalBackupS3SSE string `name:"logical_backup_s3_sse" default:"AES256"` } // Config describes operator config From 052940862ae96756a3643aab3ade1a3fba004908 Mon Sep 17 00:00:00 2001 From: Jonas Brunsgaard Date: Wed, 27 Nov 2019 16:43:46 +0100 Subject: [PATCH 08/21] Introduce crds directory for compatibility with Helm v3 (#738) * Introduce crds directory for compatibility with Helm v3 This commit introduce a crd directory for the helm chart which has all custom resource definitions. The files in the crd directory is plain YAML. The crds got the label `app.kubernetes.io/name: postgres-operator` and removes all the templating. Helm v3 ignores the objects from the `templates` directory which have a `crd-install` hook. This commit addes templates/crds.yaml which generates YAMLs for CRDs. The hooks from these CRDs are detected by Helm v2 as well as v3. Helm v2 executes the hook and Helm v3 ignores the hook (YAML files are not applied) The approach is inspired by the prometheus-operator chart helm/charts@89b233eef6dbc1b6fac418bde3a5a6f4e14406d4 --- .../crds/operatorconfigurations.yaml | 41 +++++++ .../postgres-operator/crds/postgresqls.yaml | 53 +++++++++ charts/postgres-operator/templates/crds.yaml | 6 + .../templates/customrresourcedefinition.yaml | 103 ------------------ docs/quickstart.md | 24 ++-- 5 files changed, 112 insertions(+), 115 deletions(-) create mode 100644 charts/postgres-operator/crds/operatorconfigurations.yaml create mode 100644 charts/postgres-operator/crds/postgresqls.yaml create mode 100644 charts/postgres-operator/templates/crds.yaml delete mode 100644 charts/postgres-operator/templates/customrresourcedefinition.yaml diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml new file mode 100644 index 000000000..acf132edd --- /dev/null +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -0,0 +1,41 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: operatorconfigurations.acid.zalan.do + labels: + app.kubernetes.io/name: postgres-operator + annotations: + "helm.sh/hook": crd-install +spec: + group: acid.zalan.do + names: + kind: OperatorConfiguration + listKind: OperatorConfigurationList + plural: operatorconfigurations + singular: operatorconfiguration + shortNames: + - opconfig + additionalPrinterColumns: + - name: Image + type: string + description: Spilo image to be used for Pods + JSONPath: .configuration.docker_image + - name: Cluster-Label + type: string + description: Label for K8s resources created by operator + JSONPath: .configuration.kubernetes.cluster_name_label + - name: Service-Account + type: string + description: Name of service account to be used + JSONPath: .configuration.kubernetes.pod_service_account_name + - name: Min-Instances + type: integer + description: Minimum number of instances per Postgres cluster + JSONPath: .configuration.min_instances + - name: Age + type: date + JSONPath: .metadata.creationTimestamp + scope: Namespaced + subresources: + status: {} + version: v1 diff --git a/charts/postgres-operator/crds/postgresqls.yaml b/charts/postgres-operator/crds/postgresqls.yaml new file mode 100644 index 000000000..c7505ed67 --- /dev/null +++ b/charts/postgres-operator/crds/postgresqls.yaml @@ -0,0 +1,53 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: postgresqls.acid.zalan.do + labels: + app.kubernetes.io/name: postgres-operator + annotations: + "helm.sh/hook": crd-install +spec: + group: acid.zalan.do + names: + kind: postgresql + listKind: postgresqlList + plural: postgresqls + singular: postgresql + shortNames: + - pg + additionalPrinterColumns: + - name: Team + type: string + description: Team responsible for Postgres CLuster + JSONPath: .spec.teamId + - name: Version + type: string + description: PostgreSQL version + JSONPath: .spec.postgresql.version + - name: Pods + type: integer + description: Number of Pods per Postgres cluster + JSONPath: .spec.numberOfInstances + - name: Volume + type: string + description: Size of the bound volume + JSONPath: .spec.volume.size + - name: CPU-Request + type: string + description: Requested CPU for Postgres containers + JSONPath: .spec.resources.requests.cpu + - name: Memory-Request + type: string + description: Requested memory for Postgres containers + JSONPath: .spec.resources.requests.memory + - name: Age + type: date + JSONPath: .metadata.creationTimestamp + - name: Status + type: string + description: Current sync status of postgresql resource + JSONPath: .status.PostgresClusterStatus + scope: Namespaced + subresources: + status: {} + version: v1 diff --git a/charts/postgres-operator/templates/crds.yaml b/charts/postgres-operator/templates/crds.yaml new file mode 100644 index 000000000..733830014 --- /dev/null +++ b/charts/postgres-operator/templates/crds.yaml @@ -0,0 +1,6 @@ +{{ if .Values.crd.create }} +{{- range $path, $bytes := .Files.Glob "crds/*.yaml" }} +{{ $.Files.Get $path }} +--- +{{- end }} +{{- end }} diff --git a/charts/postgres-operator/templates/customrresourcedefinition.yaml b/charts/postgres-operator/templates/customrresourcedefinition.yaml deleted file mode 100644 index 88ee1b614..000000000 --- a/charts/postgres-operator/templates/customrresourcedefinition.yaml +++ /dev/null @@ -1,103 +0,0 @@ -{{ if .Values.crd.create }} -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: postgresqls.acid.zalan.do - labels: - app.kubernetes.io/name: {{ template "postgres-operator.name" . }} - helm.sh/chart: {{ template "postgres-operator.chart" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} - annotations: - "helm.sh/hook": crd-install -spec: - group: acid.zalan.do - names: - kind: postgresql - listKind: postgresqlList - plural: postgresqls - singular: postgresql - shortNames: - - pg - additionalPrinterColumns: - - name: Team - type: string - description: Team responsible for Postgres CLuster - JSONPath: .spec.teamId - - name: Version - type: string - description: PostgreSQL version - JSONPath: .spec.postgresql.version - - name: Pods - type: integer - description: Number of Pods per Postgres cluster - JSONPath: .spec.numberOfInstances - - name: Volume - type: string - description: Size of the bound volume - JSONPath: .spec.volume.size - - name: CPU-Request - type: string - description: Requested CPU for Postgres containers - JSONPath: .spec.resources.requests.cpu - - name: Memory-Request - type: string - description: Requested memory for Postgres containers - JSONPath: .spec.resources.requests.memory - - name: Age - type: date - JSONPath: .metadata.creationTimestamp - - name: Status - type: string - description: Current sync status of postgresql resource - JSONPath: .status.PostgresClusterStatus - scope: Namespaced - subresources: - status: {} - version: v1 ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: operatorconfigurations.acid.zalan.do - labels: - app.kubernetes.io/name: {{ template "postgres-operator.name" . }} - helm.sh/chart: {{ template "postgres-operator.chart" . }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} - annotations: - "helm.sh/hook": crd-install -spec: - group: acid.zalan.do - names: - kind: OperatorConfiguration - listKind: OperatorConfigurationList - plural: operatorconfigurations - singular: operatorconfiguration - shortNames: - - opconfig - additionalPrinterColumns: - - name: Image - type: string - description: Spilo image to be used for Pods - JSONPath: .configuration.docker_image - - name: Cluster-Label - type: string - description: Label for K8s resources created by operator - JSONPath: .configuration.kubernetes.cluster_name_label - - name: Service-Account - type: string - description: Name of service account to be used - JSONPath: .configuration.kubernetes.pod_service_account_name - - name: Min-Instances - type: integer - description: Minimum number of instances per Postgres cluster - JSONPath: .configuration.min_instances - - name: Age - type: date - JSONPath: .metadata.creationTimestamp - scope: Namespaced - subresources: - status: {} - version: v1 -{{ end }} diff --git a/docs/quickstart.md b/docs/quickstart.md index 500d4db30..8fca8b62c 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -73,22 +73,22 @@ manifest. ### Helm chart Alternatively, the operator can be installed by using the provided [Helm](https://helm.sh/) -chart which saves you the manual steps. Therefore, install the helm CLI on your -machine. After initializing helm (and its server component Tiller) in your local -cluster you can install the operator chart. You can define a release name that -is prepended to the operator resource's names. - -Use `--name zalando` to match with the default service account name as older -operator versions do not support custom names for service accounts. To use -CRD-based configuration you need to specify the [values-crd yaml file](../charts/postgres-operator/values-crd.yaml). +chart which saves you the manual steps. Clone this repo and change directory to +the repo root. With Helm v3 installed you should be able to run: ```bash -# 1) initialize helm -helm init -# 2) install postgres-operator chart -helm install --name zalando ./charts/postgres-operator +helm install postgres-operator ./charts/postgres-operator ``` +To use CRD-based configuration you need to specify the [values-crd yaml file](../charts/postgres-operator/values-crd.yaml). + +```bash +helm install postgres-operator ./charts/postgres-operator -f ./charts/postgres-operator/values-crd.yaml +``` + +The chart works with both Helm 2 and Helm 3. Documentation for installing +applications with helm2 can be found in the [helm2 docs](https://v2.helm.sh/docs/). + ### Operator Lifecycle Manager (OLM) The [Operator Lifecycle Manager (OLM)](https://github.com/operator-framework/operator-lifecycle-manager) From a3b34f146f1be5cd0e6e71b8882a5cdd1be62639 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Thu, 28 Nov 2019 12:02:05 +0100 Subject: [PATCH 09/21] Add CRD validation (#599) * add CRD manifests with validation * update documentation * patroni slots is not an array but a nested hash map * make deps call tools * cover validation in docs and export it in crds.go * add toggle to disable creation of CRD validation and document it * use templated service account also for CRD-configured helm deployment --- Makefile | 2 +- .../crds/operatorconfigurations.yaml | 259 +++++ .../postgres-operator/crds/postgresqls.yaml | 310 ++++++ .../templates/operatorconfiguration.yaml | 2 +- charts/postgres-operator/values-crd.yaml | 23 +- charts/postgres-operator/values.yaml | 13 +- delivery.yaml | 2 +- docs/administrator.md | 82 +- docs/developer.md | 4 +- docs/quickstart.md | 27 +- docs/reference/operator_parameters.md | 18 +- manifests/complete-postgres-manifest.yaml | 52 +- manifests/configmap.yaml | 9 +- manifests/operatorconfiguration.crd.yaml | 276 ++++++ ...gresql-operator-default-configuration.yaml | 16 +- manifests/postgresql.crd.yaml | 327 +++++++ pkg/apis/acid.zalan.do/v1/crds.go | 922 +++++++++++++++++- .../v1/operator_configuration_type.go | 1 + .../acid.zalan.do/v1/zz_generated.deepcopy.go | 5 + pkg/controller/controller.go | 6 +- pkg/controller/operator_config.go | 1 + pkg/controller/util.go | 10 +- pkg/util/config/config.go | 9 +- run_operator_locally.sh | 2 +- 24 files changed, 2270 insertions(+), 108 deletions(-) create mode 100644 manifests/operatorconfiguration.crd.yaml create mode 100644 manifests/postgresql.crd.yaml diff --git a/Makefile b/Makefile index 8710f17ee..f42cfe09a 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ vet: @go vet $(PKG) @staticcheck $(PKG) -deps: +deps: tools GO111MODULE=on go mod vendor test: diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index acf132edd..ff92bc064 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -39,3 +39,262 @@ spec: subresources: status: {} version: v1 + validation: + openAPIV3Schema: + type: object + required: + - kind + - apiVersion + - configuration + properties: + kind: + type: string + enum: + - OperatorConfiguration + apiVersion: + type: string + enum: + - acid.zalan.do/v1 + configuration: + type: object + properties: + docker_image: + type: string + enable_crd_validation: + type: boolean + enable_shm_volume: + type: boolean + etcd_host: + type: string + max_instances: + type: integer + minimum: -1 # -1 = disabled + min_instances: + type: integer + minimum: -1 # -1 = disabled + resync_period: + type: string + repair_period: + type: string + set_memory_request_to_limit: + type: boolean + sidecar_docker_images: + type: object + additionalProperties: + type: string + workers: + type: integer + minimum: 1 + users: + type: object + properties: + replication_username: + type: string + super_username: + type: string + kubernetes: + type: object + properties: + cluster_domain: + type: string + cluster_labels: + type: object + additionalProperties: + type: string + cluster_name_label: + type: string + custom_pod_annotations: + type: object + additionalProperties: + type: string + enable_pod_antiaffinity: + type: boolean + enable_pod_disruption_budget: + type: boolean + infrastructure_roles_secret_name: + type: string + inherited_labels: + type: array + items: + type: string + node_readiness_label: + type: object + additionalProperties: + 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: + - "ordered_ready" + - "parallel" + 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: + type: string + watched_namespace: + type: string + postgres_pod_resources: + type: object + properties: + 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: + 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: + db_hosted_zone: + type: string + enable_master_load_balancer: + type: boolean + enable_replica_load_balancer: + type: boolean + custom_service_annotations: + type: object + additionalProperties: + type: string + master_dns_name_format: + type: string + replica_dns_name_format: + type: string + aws_or_gcp: + type: object + properties: + 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: + logical_backup_schedule: + type: string + pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' + logical_backup_docker_image: + type: string + logical_backup_s3_bucket: + type: string + logical_backup_s3_endpoint: + type: string + logical_backup_s3_sse: + type: string + logical_backup_s3_access_key_id: + type: string + logical_backup_s3_secret_access_key: + type: string + debug: + type: object + properties: + debug_logging: + type: boolean + enable_database_access: + type: boolean + teams_api: + type: object + properties: + 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: + type: string + protected_role_names: + type: array + items: + type: string + team_admin_role: + type: string + team_api_role_configuration: + type: object + additionalProperties: + type: string + teams_api_url: + type: string + logging_rest_api: + type: object + properties: + api_port: + type: integer + cluster_history_entries: + type: integer + ring_log_lines: + type: integer + scalyr: + type: object + properties: + 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 diff --git a/charts/postgres-operator/crds/postgresqls.yaml b/charts/postgres-operator/crds/postgresqls.yaml index c7505ed67..a8c5f2954 100644 --- a/charts/postgres-operator/crds/postgresqls.yaml +++ b/charts/postgres-operator/crds/postgresqls.yaml @@ -51,3 +51,313 @@ spec: subresources: status: {} version: v1 + validation: + openAPIV3Schema: + type: object + required: + - kind + - apiVersion + - spec + properties: + kind: + type: string + enum: + - postgresql + apiVersion: + type: string + enum: + - acid.zalan.do/v1 + spec: + type: object + required: + - numberOfInstances + - teamId + - postgresql + properties: + allowedSourceRanges: + type: array + nullable: true + items: + 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: + - cluster + properties: + 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 + 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]))$' + # The regexp matches the date-time format (RFC 3339 Section 5.6) that specifies a timezone as an offset relative to UTC + # Example: 1996-12-19T16:39:57-08:00 + # Note: this field requires a timezone + uid: + format: uuid + type: string + databases: + type: object + additionalProperties: + type: string + # Note: usernames 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: # deprecated + type: array + nullable: true + items: + type: object + additionalProperties: true + initContainers: + type: array + nullable: true + items: + type: object + additionalProperties: true + logicalBackupSchedule: + type: string + pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' + maintenanceWindows: + type: array + items: + 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: 0 + patroni: + type: object + properties: + initdb: + type: object + additionalProperties: + type: string + pg_hba: + type: array + items: + type: string + slots: + type: object + additionalProperties: + type: object + additionalProperties: + type: string + ttl: + type: integer + loop_wait: + type: integer + retry_timeout: + type: integer + maximum_lag_on_failover: + type: integer + podAnnotations: + type: object + additionalProperties: + type: string + pod_priority_class_name: # deprecated + type: string + podPriorityClassName: + type: string + postgresql: + type: object + required: + - version + properties: + version: + type: string + enum: + - "9.3" + - "9.4" + - "9.5" + - "9.6" + - "10" + - "11" + - "12" + parameters: + type: object + additionalProperties: + type: string + replicaLoadBalancer: # deprecated + type: boolean + resources: + type: object + required: + - requests + - limits + properties: + limits: + type: object + required: + - cpu + - memory + properties: + cpu: + type: string + # Decimal natural followed by m, or decimal natural followed by + # dot followed by up to three decimal digits. + # + # This is because the Kubernetes CPU resource has millis as the + # maximum precision. The actual values are checked in code + # because the regular expression would be huge and horrible and + # not very helpful in validation error messages; this one checks + # only the format of the given number. + # + # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu + pattern: '^(\d+m|\d+\.\d{1,3})$' + # Note: the value specified here must not be zero or be lower + # than the corresponding request. + memory: + type: string + # You can express memory as a plain integer or as a fixed-point + # integer using one of these suffixes: E, P, T, G, M, k. You can + # also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki + # + # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-memory + pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' + # Note: the value specified here must not be zero or be lower + # than the corresponding request. + requests: + type: object + required: + - cpu + - memory + properties: + cpu: + type: string + # Decimal natural followed by m, or decimal natural followed by + # dot followed by up to three decimal digits. + # + # This is because the Kubernetes CPU resource has millis as the + # maximum precision. The actual values are checked in code + # because the regular expression would be huge and horrible and + # not very helpful in validation error messages; this one checks + # only the format of the given number. + # + # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu + pattern: '^(\d+m|\d+\.\d{1,3})$' + # Note: the value specified here must not be zero or be higher + # than the corresponding limit. + memory: + type: string + # You can express memory as a plain integer or as a fixed-point + # integer using one of these suffixes: E, P, T, G, M, k. You can + # also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki + # + # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-memory + pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' + # Note: the value specified here must not be zero or be higher + # than the corresponding limit. + sidecars: + type: array + nullable: true + items: + type: object + additionalProperties: true + spiloFSGroup: + type: integer + standby: + type: object + required: + - s3_wal_path + properties: + s3_wal_path: + type: string + teamId: + type: string + tolerations: + type: array + items: + type: object + required: + - key + - operator + - effect + properties: + key: + type: string + operator: + type: string + enum: + - Equal + - Exists + value: + type: string + effect: + type: string + enum: + - NoExecute + - NoSchedule + - PreferNoSchedule + tolerationSeconds: + type: integer + useLoadBalancer: # deprecated + type: boolean + users: + type: object + additionalProperties: + type: array + nullable: true + description: "Role flags specified here must not contradict each other" + items: + type: string + enum: + - bypassrls + - BYPASSRLS + - nobypassrls + - NOBYPASSRLS + - createdb + - CREATEDB + - nocreatedb + - NOCREATEDB + - createrole + - CREATEROLE + - nocreaterole + - NOCREATEROLE + - inherit + - INHERIT + - noinherit + - NOINHERIT + - login + - LOGIN + - nologin + - NOLOGIN + - replication + - REPLICATION + - noreplication + - NOREPLICATION + - superuser + - SUPERUSER + - nosuperuser + - NOSUPERUSER + volume: + type: object + required: + - size + properties: + size: + type: string + pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' + # Note: the value specified here must not be zero. + storageClass: + type: string + subPath: + type: string diff --git a/charts/postgres-operator/templates/operatorconfiguration.yaml b/charts/postgres-operator/templates/operatorconfiguration.yaml index c6e9f78b7..6a301c1fb 100644 --- a/charts/postgres-operator/templates/operatorconfiguration.yaml +++ b/charts/postgres-operator/templates/operatorconfiguration.yaml @@ -14,7 +14,7 @@ configuration: {{ toYaml .Values.configUsers | indent 4 }} kubernetes: oauth_token_secret_name: {{ template "postgres-operator.fullname" . }} - pod_service_account_name: operator + pod_service_account_name: {{ include "postgres-operator.serviceAccountName" . }} {{ toYaml .Values.configKubernetes | indent 4 }} postgres_pod_resources: {{ toYaml .Values.configPostgresPodResources | indent 4 }} diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index af05ae56c..c6f11e493 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. @@ -57,7 +59,10 @@ configKubernetes: # label assigned to Kubernetes objects created by the operator cluster_name_label: cluster-name # additional annotations to add to every database pod - custom_pod_annotations: + # custom_pod_annotations: + # keya: valuea + # keyb: valueb + # toggles pod anti affinity on the Postgres pods enable_pod_antiaffinity: false # toggles PDB to set to MinAvailabe 0 or 1 @@ -74,7 +79,8 @@ configKubernetes: # master_pod_move_timeout: 20m # set of labels that a running and active node should possess to be considered ready - # node_readiness_label: "" + # node_readiness_label: + # status: ready # name of the secret containing the OAuth2 token to pass to the teams API # oauth_token_secret_name: postgresql-operator @@ -186,7 +192,7 @@ configAwsOrGcp: configLogicalBackup: # image for pods of the logical backup job (example runs pg_dumpall) logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" - # S3 Access Key ID + # S3 Access Key ID logical_backup_s3_access_key_id: "" # S3 bucket to store backup results logical_backup_s3_bucket: "my-bucket-url" @@ -194,7 +200,7 @@ configLogicalBackup: logical_backup_s3_endpoint: "" # S3 Secret Access Key logical_backup_s3_secret_access_key: "" - # S3 server side encription + # S3 server side encription logical_backup_s3_sse: "AES256" # backup schedule in the cron format logical_backup_schedule: "30 00 * * *" @@ -214,7 +220,8 @@ configTeamsApi: # operator will add all team member roles to this group and add a pg_hba line pam_role_name: zalandos # List of teams which members need the superuser role in each Postgres cluster - # postgres_superuser_teams: "postgres_superusers" + # postgres_superuser_teams: + # - postgres_superusers # List of roles that cannot be overwritten by an application, team or infrastructure role protected_role_names: @@ -228,7 +235,7 @@ configTeamsApi: # teams_api_url: http://fake-teams-api.default.svc.cluster.local # Scalyr is a log management tool that Zalando uses as a sidecar -scalyr: +configScalyr: # API key for the Scalyr sidecar # scalyr_api_key: "" @@ -257,9 +264,7 @@ serviceAccount: create: true # The name of the ServiceAccount to use. # If not set and create is true, a name is generated using the fullname template - # When relying solely on the OperatorConfiguration CRD, this value has to be "operator" - # Otherwise, the operator tries to use the "default" service account which is forbidden - name: operator + name: priorityClassName: "" diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index b572b5844..ae9e06fe9 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. @@ -55,7 +57,8 @@ configKubernetes: # label assigned to Kubernetes objects created by the operator cluster_name_label: version # annotations attached to each database pod - # custom_pod_annotations: keya:valuea + # custom_pod_annotations: keya:valuea,keyb:valueb + # toggles pod anti affinity on the Postgres pods enable_pod_antiaffinity: "false" # toggles PDB to set to MinAvailabe 0 or 1 @@ -136,9 +139,9 @@ configLoadBalancer: # toggles service type load balancer pointing to the replica pod of the cluster enable_replica_load_balancer: "false" # defines the DNS name string template for the master load balancer cluster - master_dns_name_format: '{cluster}.{team}.staging.{hostedzone}' + master_dns_name_format: '{cluster}.{team}.{hostedzone}' # defines the DNS name string template for the replica load balancer cluster - replica_dns_name_format: '{cluster}-repl.{team}.staging.{hostedzone}' + replica_dns_name_format: '{cluster}-repl.{team}.{hostedzone}' # options to aid debugging of the operator itself configDebug: @@ -180,7 +183,7 @@ configAwsOrGcp: configLogicalBackup: # image for pods of the logical backup job (example runs pg_dumpall) logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" - # S3 Access Key ID + # S3 Access Key ID logical_backup_s3_access_key_id: "" # S3 bucket to store backup results logical_backup_s3_bucket: "my-bucket-url" @@ -188,7 +191,7 @@ configLogicalBackup: logical_backup_s3_endpoint: "" # S3 Secret Access Key logical_backup_s3_secret_access_key: "" - # S3 server side encription + # S3 server side encription logical_backup_s3_sse: "AES256" # backup schedule in the cron format logical_backup_schedule: "30 00 * * *" diff --git a/delivery.yaml b/delivery.yaml index ef249292c..be35d3e27 100644 --- a/delivery.yaml +++ b/delivery.yaml @@ -28,7 +28,7 @@ pipeline: IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator-test fi export IMAGE - make tools deps docker + make deps docker - desc: 'Run unit tests' cmd: | export PATH=$PATH:$HOME/go/bin diff --git a/docs/administrator.md b/docs/administrator.md index ab5368e7d..5cde06ade 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 @@ -32,7 +56,7 @@ By default, the operator watches the namespace it is deployed to. You can change this by setting the `WATCHED_NAMESPACE` var in the `env` section of the [operator deployment](../manifests/postgres-operator.yaml) manifest or by altering the `watched_namespace` field in the operator -[ConfigMap](../manifests/configmap.yaml#L79). +[configuration](../manifests/postgresql-operator-default-configuration.yaml#L49). In the case both are set, the env var takes the precedence. To make the operator listen to all namespaces, explicitly set the field/env var to "`*`". @@ -115,7 +139,7 @@ that are aggregated into the K8s [default roles](https://kubernetes.io/docs/refe To ensure Postgres pods are running on nodes without any other application pods, you can use [taints and tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) -and configure the required toleration in the operator ConfigMap. +and configure the required toleration in the operator configuration. As an example you can set following node taint: @@ -136,6 +160,21 @@ data: ... ``` +For an OperatorConfiguration resource the toleration should be defined like +this: + +```yaml +apiVersion: "acid.zalan.do/v1" +kind: OperatorConfiguration +metadata: + name: postgresql-configuration +configuration: + kubernetes: + toleration: + postgres: "key:postgres,operator:Exists,effect:NoSchedule" + ... +``` + Note that the K8s version 1.13 brings [taint-based eviction](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/#taint-based-evictions) to the beta stage and enables it by default. Postgres pods by default receive tolerations for `unreachable` and `noExecute` taints with the timeout of `5m`. @@ -148,7 +187,7 @@ completely, specify the toleration by leaving out the `tolerationSeconds` value To ensure Postgres pods are running on different topologies, you can use [pod anti affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/) -and configure the required topology in the operator ConfigMap. +and configure the required topology in the operator configuration. Enable pod anti affinity by adding following line to the operator ConfigMap: @@ -161,21 +200,22 @@ data: enable_pod_antiaffinity: "true" ``` -By default the topology key for the pod anti affinity is set to -`kubernetes.io/hostname`, you can set another topology key e.g. -`failure-domain.beta.kubernetes.io/zone` by adding following line to the -operator ConfigMap, see [built-in node labels](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#interlude-built-in-node-labels) for available topology keys: +Likewise, when using an OperatorConfiguration resource add: ```yaml -apiVersion: v1 -kind: ConfigMap +apiVersion: "acid.zalan.do/v1" +kind: OperatorConfiguration metadata: - name: postgres-operator -data: - enable_pod_antiaffinity: "true" - pod_antiaffinity_topology_key: "failure-domain.beta.kubernetes.io/zone" + name: postgresql-configuration +configuration: + kubernetes: + enable_pod_antiaffinity: true ``` +By default the topology key for the pod anti affinity is set to +`kubernetes.io/hostname`, you can set another topology key e.g. +`failure-domain.beta.kubernetes.io/zone`. See [built-in node labels](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#interlude-built-in-node-labels) for available topology keys. + ## Pod Disruption Budget By default the operator uses a PodDisruptionBudget (PDB) to protect the cluster @@ -280,6 +320,20 @@ data: ... ``` +**OperatorConfiguration** + +```yaml +apiVersion: "acid.zalan.do/v1" +kind: OperatorConfiguration +metadata: + name: postgresql-operator-configuration +configuration: + kubernetes: + # referencing config map with custom settings + pod_environment_configmap: postgres-pod-config + ... +``` + **referenced ConfigMap `postgres-pod-config`** ```yaml @@ -312,7 +366,7 @@ services: one for the master pod and one for replica pods. To expose these services to an outer network, one can attach load balancers to them by setting `enableMasterLoadBalancer` and/or `enableReplicaLoadBalancer` to `true` in the cluster manifest. In the case any of these variables are omitted from the -manifest, the operator configmap's settings `enable_master_load_balancer` and +manifest, the operator configuration settings `enable_master_load_balancer` and `enable_replica_load_balancer` apply. Note that the operator settings affect all Postgresql services running in all namespaces watched by the operator. diff --git a/docs/developer.md b/docs/developer.md index 490217362..f8351e28a 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -33,7 +33,7 @@ by setting the `GO111MODULE` environment variable to `on`. The make targets do this for you, so simply run ```bash -make tools deps +make deps ``` This would take a while to complete. You have to redo `make deps` every time @@ -284,6 +284,7 @@ manifest files: Postgres manifest parameters are defined in the [api package](../pkg/apis/acid.zalan.do/v1/postgresql_type.go). The operator behavior has to be implemented at least in [k8sres.go](../pkg/cluster/k8sres.go). +Validation of CRD parameters is controlled in [crd.go](../pkg/apis/acid.zalan.do/v1/crds.go). Please, reflect your changes in tests, for example in: * [config_test.go](../pkg/util/config/config_test.go) * [k8sres_test.go](../pkg/cluster/k8sres_test.go) @@ -294,6 +295,7 @@ Please, reflect your changes in tests, for example in: For the CRD-based configuration, please update the following files: * the default [OperatorConfiguration](../manifests/postgresql-operator-default-configuration.yaml) * the Helm chart's [values-crd file](../charts/postgres-operator/values.yaml) +* the CRD's [validation](../manifests/operatorconfiguration.crd.yaml) Reflect the changes in the ConfigMap configuration as well (note that numeric and boolean parameters have to use double quotes here): diff --git a/docs/quickstart.md b/docs/quickstart.md index 8fca8b62c..2da2cab7c 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -55,8 +55,8 @@ kubectl create -f manifests/postgres-operator.yaml # deployment ``` There is a [Kustomization](https://github.com/kubernetes-sigs/kustomize) -manifest that [combines the mentioned resources](../manifests/kustomization.yaml) - -it can be used with kubectl 1.14 or newer as easy as: +manifest that [combines the mentioned resources](../manifests/kustomization.yaml) +(except for the CRD) - it can be used with kubectl 1.14 or newer as easy as: ```bash kubectl apply -k github.com/zalando/postgres-operator/manifests @@ -86,8 +86,9 @@ To use CRD-based configuration you need to specify the [values-crd yaml file](.. helm install postgres-operator ./charts/postgres-operator -f ./charts/postgres-operator/values-crd.yaml ``` -The chart works with both Helm 2 and Helm 3. Documentation for installing -applications with helm2 can be found in the [helm2 docs](https://v2.helm.sh/docs/). +The chart works with both Helm 2 and Helm 3. The `crd-install` hook from v2 will +be skipped with warning when using v3. Documentation for installing applications +with Helm 2 can be found in the [v2 docs](https://v2.helm.sh/docs/). ### Operator Lifecycle Manager (OLM) @@ -119,15 +120,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 a024aad1f..e16282fd2 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -29,21 +29,20 @@ configuration. To test the CRD-based configuration locally, use the following ```bash + kubectl create -f manifests/operatorconfiguration.crd.yaml # registers the CRD + kubectl create -f manifests/postgresql-operator-default-configuration.yaml + kubectl create -f manifests/operator-service-account-rbac.yaml kubectl create -f manifests/postgres-operator.yaml # set the env var as mentioned above - kubectl create -f manifests/postgresql-operator-default-configuration.yaml + kubectl get operatorconfigurations postgresql-operator-default-configuration -o yaml ``` - Note that the operator first attempts to register the CRD of the - `OperatorConfiguration` and then waits for an instance to be created. In - between these two event the operator pod may be failing since it cannot fetch - the not-yet-existing `OperatorConfiguration` instance. The CRD-based configuration is more powerful than the one based on ConfigMaps and should be used unless there is a compatibility requirement to use an already existing configuration. Even in that case, it should be rather straightforward -to convert the configmap based configuration into the CRD-based one and restart -the operator. The ConfigMaps-based configuration will be deprecated and +to convert the ConfigMap-based configuration into the CRD-based one and restart +the operator. The ConfigMap-based configuration will be deprecated and subsequently removed in future releases. Note that for the CRD-based configuration groups of configuration options below @@ -71,6 +70,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/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index 34dd6cf83..f8495caad 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -13,7 +13,7 @@ spec: teamId: "ACID" volume: size: 1Gi -# storageClass: my-sc +# storageClass: my-sc numberOfInstances: 2 users: # Application/Robot users zalando: @@ -30,7 +30,7 @@ spec: # Expert section enableShmVolume: true -# spiloFSGroup: 103 +# spiloFSGroup: 103 postgresql: version: "11" parameters: @@ -52,13 +52,13 @@ spec: pg_hba: - hostssl all all 0.0.0.0/0 md5 - host all all 0.0.0.0/0 md5 -# slots: -# - permanent_physical_1: -# type: physical -# - permanent_logical_1: -# type: logical -# database: foo -# plugin: pgoutput +# slots: +# permanent_physical_1: +# type: physical +# permanent_logical_1: +# type: logical +# database: foo +# plugin: pgoutput ttl: 30 loop_wait: &loop_wait 10 retry_timeout: 10 @@ -66,28 +66,28 @@ spec: # restore a Postgres DB with point-in-time-recovery # with a non-empty timestamp, clone from an S3 bucket using the latest backup before the timestamp # with an empty/absent timestamp, clone from an existing alive cluster using pg_basebackup -# clone: -# uid: "efd12e58-5786-11e8-b5a7-06148230260c" -# cluster: "acid-batman" -# timestamp: "2017-12-19T12:40:33+01:00" # timezone required (offset relative to UTC, see RFC 3339 section 5.6) -# s3_wal_path: "s3://custom/path/to/bucket" +# clone: +# uid: "efd12e58-5786-11e8-b5a7-06148230260c" +# cluster: "acid-batman" +# timestamp: "2017-12-19T12:40:33+01:00" # timezone required (offset relative to UTC, see RFC 3339 section 5.6) +# s3_wal_path: "s3://custom/path/to/bucket" # run periodic backups with k8s cron jobs -# enableLogicalBackup: true -# logicalBackupSchedule: "30 00 * * *" +# enableLogicalBackup: true +# logicalBackupSchedule: "30 00 * * *" maintenanceWindows: - 01:00-06:00 #UTC - Sat:00:00-04:00 -# sidecars: -# - name: "telegraf-sidecar" -# image: "telegraf:latest" -# resources: -# limits: -# cpu: 500m -# memory: 500Mi -# requests: -# cpu: 100m -# memory: 100Mi +# sidecars: +# - name: "telegraf-sidecar" +# image: "telegraf:latest" +# resources: +# limits: +# cpu: 500m +# memory: 500Mi +# requests: +# cpu: 100m +# memory: 100Mi # env: # - name: "USEFUL_VAR" # value: "perhaps-true" diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 40aca9716..59d3abfde 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -12,7 +12,7 @@ data: cluster_labels: application:spilo cluster_name_label: version # custom_service_annotations: "keyx:valuez,keya:valuea" - # custom_pod_annotations: "keya:valuea" + # custom_pod_annotations: "keya:valuea,keyb:valueb" db_hosted_zone: db.example.com debug_logging: "true" # default_cpu_limit: "3" @@ -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" @@ -41,7 +42,7 @@ data: # logical_backup_s3_secret_access_key: "" # logical_backup_s3_sse: "AES256" # logical_backup_schedule: "30 00 * * *" - master_dns_name_format: "{cluster}.{team}.staging.{hostedzone}" + master_dns_name_format: "{cluster}.{team}.{hostedzone}" # master_pod_move_timeout: 10m # max_instances: "-1" # min_instances: "-1" @@ -64,11 +65,11 @@ data: ready_wait_interval: 3s ready_wait_timeout: 30s repair_period: 5m - replica_dns_name_format: "{cluster}-repl.{team}.staging.{hostedzone}" + replica_dns_name_format: "{cluster}-repl.{team}.{hostedzone}" replication_username: standby resource_check_interval: 3s resource_check_timeout: 10m - resync_period: 5m + resync_period: 30m ring_log_lines: "100" secret_name_template: "{username}.{cluster}.credentials" # sidecar_docker_images: "" diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml new file mode 100644 index 000000000..753415a15 --- /dev/null +++ b/manifests/operatorconfiguration.crd.yaml @@ -0,0 +1,276 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: operatorconfigurations.acid.zalan.do +spec: + group: acid.zalan.do + names: + kind: OperatorConfiguration + listKind: OperatorConfigurationList + plural: operatorconfigurations + singular: operatorconfiguration + shortNames: + - opconfig + scope: Namespaced + subresources: + status: {} + version: v1 + validation: + openAPIV3Schema: + type: object + required: + - kind + - apiVersion + - configuration + properties: + kind: + type: string + enum: + - OperatorConfiguration + apiVersion: + type: string + enum: + - acid.zalan.do/v1 + configuration: + type: object + properties: + docker_image: + type: string + enable_crd_validation: + type: boolean + enable_shm_volume: + type: boolean + etcd_host: + type: string + max_instances: + type: integer + minimum: -1 # -1 = disabled + min_instances: + type: integer + minimum: -1 # -1 = disabled + resync_period: + type: string + repair_period: + type: string + set_memory_request_to_limit: + type: boolean + sidecar_docker_images: + type: object + additionalProperties: + type: string + workers: + type: integer + minimum: 1 + users: + type: object + properties: + replication_username: + type: string + super_username: + type: string + kubernetes: + type: object + properties: + cluster_domain: + type: string + cluster_labels: + type: object + additionalProperties: + type: string + cluster_name_label: + type: string + custom_pod_annotations: + type: object + additionalProperties: + type: string + enable_pod_antiaffinity: + type: boolean + enable_pod_disruption_budget: + type: boolean + infrastructure_roles_secret_name: + type: string + inherited_labels: + type: array + items: + type: string + node_readiness_label: + type: object + additionalProperties: + 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: + - "ordered_ready" + - "parallel" + 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: + type: string + watched_namespace: + type: string + postgres_pod_resources: + type: object + properties: + 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: + 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: + db_hosted_zone: + type: string + enable_master_load_balancer: + type: boolean + enable_replica_load_balancer: + type: boolean + custom_service_annotations: + type: object + additionalProperties: + type: string + master_dns_name_format: + type: string + replica_dns_name_format: + type: string + aws_or_gcp: + type: object + properties: + 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: + logical_backup_schedule: + type: string + pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' + logical_backup_docker_image: + type: string + logical_backup_s3_bucket: + type: string + logical_backup_s3_endpoint: + type: string + logical_backup_s3_sse: + type: string + logical_backup_s3_access_key_id: + type: string + logical_backup_s3_secret_access_key: + type: string + debug: + type: object + properties: + debug_logging: + type: boolean + enable_database_access: + type: boolean + teams_api: + type: object + properties: + 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: + type: string + protected_role_names: + type: array + items: + type: string + team_admin_role: + type: string + team_api_role_configuration: + type: object + additionalProperties: + type: string + teams_api_url: + type: string + logging_rest_api: + type: object + properties: + api_port: + type: integer + cluster_history_entries: + type: integer + ring_log_lines: + type: integer + scalyr: + type: object + properties: + 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 diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index 94f91f1f0..7a867d5df 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 @@ -27,24 +28,25 @@ configuration: # keyb: valueb enable_pod_antiaffinity: false enable_pod_disruption_budget: true - # infrastructure_roles_secret_name: "" + # infrastructure_roles_secret_name: postgresql-infrastructure-roles # inherited_labels: # - application # - environment - # node_readiness_label: "" + # node_readiness_label: + # status: ready oauth_token_secret_name: postgresql-operator pdb_name_format: "postgres-{cluster}-pdb" pod_antiaffinity_topology_key: "kubernetes.io/hostname" # pod_environment_configmap: "" pod_management_policy: "ordered_ready" pod_role_label: spilo-role - pod_service_account_name: operator + pod_service_account_name: zalando-postgres-operator pod_terminate_grace_period: 5m secret_name_template: "{username}.{cluster}.credentials.{tprkind}.{tprgroup}" # spilo_fsgroup: 103 spilo_privileged: false # toleration: {} - # watched_namespace:"" + # watched_namespace: "" postgres_pod_resources: default_cpu_limit: "3" default_cpu_request: 100m @@ -74,7 +76,6 @@ configuration: # log_s3_bucket: "" # wal_s3_bucket: "" logical_backup: - log_s3_bucket: "" logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" logical_backup_s3_access_key_id: "" logical_backup_s3_bucket: "my-bucket-url" @@ -91,9 +92,10 @@ configuration: enable_teams_api: false # pam_configuration: "" pam_role_name: zalandos - # postgres_superuser_teams: "postgres_superusers" + # postgres_superuser_teams: + # - postgres_superusers protected_role_names: - - admin + - admin team_admin_role: admin team_api_role_configuration: log_statement: all diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml new file mode 100644 index 000000000..4a578b324 --- /dev/null +++ b/manifests/postgresql.crd.yaml @@ -0,0 +1,327 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: postgresqls.acid.zalan.do +spec: + group: acid.zalan.do + names: + kind: postgresql + listKind: postgresqlList + plural: postgresqls + singular: postgresql + shortNames: + - pg + scope: Namespaced + subresources: + status: {} + version: v1 + validation: + openAPIV3Schema: + type: object + required: + - kind + - apiVersion + - spec + properties: + kind: + type: string + enum: + - postgresql + apiVersion: + type: string + enum: + - acid.zalan.do/v1 + spec: + type: object + required: + - numberOfInstances + - teamId + - postgresql + properties: + allowedSourceRanges: + type: array + nullable: true + items: + 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: + - cluster + properties: + 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 + 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]))$' + # The regexp matches the date-time format (RFC 3339 Section 5.6) that specifies a timezone as an offset relative to UTC + # Example: 1996-12-19T16:39:57-08:00 + # Note: this field requires a timezone + uid: + format: uuid + type: string + databases: + type: object + additionalProperties: + type: string + # Note: usernames 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: # deprecated + type: array + nullable: true + items: + type: object + additionalProperties: true + initContainers: + type: array + nullable: true + items: + type: object + additionalProperties: true + logicalBackupSchedule: + type: string + pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' + maintenanceWindows: + type: array + items: + 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: 0 + patroni: + type: object + properties: + initdb: + type: object + additionalProperties: + type: string + pg_hba: + type: array + items: + type: string + slots: + type: object + additionalProperties: + type: object + additionalProperties: + type: string + ttl: + type: integer + loop_wait: + type: integer + retry_timeout: + type: integer + maximum_lag_on_failover: + type: integer + podAnnotations: + type: object + additionalProperties: + type: string + pod_priority_class_name: # deprecated + type: string + podPriorityClassName: + type: string + postgresql: + type: object + required: + - version + properties: + version: + type: string + enum: + - "9.3" + - "9.4" + - "9.5" + - "9.6" + - "10" + - "11" + - "12" + parameters: + type: object + additionalProperties: + type: string + replicaLoadBalancer: # deprecated + type: boolean + resources: + type: object + required: + - requests + - limits + properties: + limits: + type: object + required: + - cpu + - memory + properties: + cpu: + type: string + # Decimal natural followed by m, or decimal natural followed by + # dot followed by up to three decimal digits. + # + # This is because the Kubernetes CPU resource has millis as the + # maximum precision. The actual values are checked in code + # because the regular expression would be huge and horrible and + # not very helpful in validation error messages; this one checks + # only the format of the given number. + # + # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu + pattern: '^(\d+m|\d+\.\d{1,3})$' + # Note: the value specified here must not be zero or be lower + # than the corresponding request. + memory: + type: string + # You can express memory as a plain integer or as a fixed-point + # integer using one of these suffixes: E, P, T, G, M, k. You can + # also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki + # + # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-memory + pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' + # Note: the value specified here must not be zero or be lower + # than the corresponding request. + requests: + type: object + required: + - cpu + - memory + properties: + cpu: + type: string + # Decimal natural followed by m, or decimal natural followed by + # dot followed by up to three decimal digits. + # + # This is because the Kubernetes CPU resource has millis as the + # maximum precision. The actual values are checked in code + # because the regular expression would be huge and horrible and + # not very helpful in validation error messages; this one checks + # only the format of the given number. + # + # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu + pattern: '^(\d+m|\d+\.\d{1,3})$' + # Note: the value specified here must not be zero or be higher + # than the corresponding limit. + memory: + type: string + # You can express memory as a plain integer or as a fixed-point + # integer using one of these suffixes: E, P, T, G, M, k. You can + # also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki + # + # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-memory + pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' + # Note: the value specified here must not be zero or be higher + # than the corresponding limit. + sidecars: + type: array + nullable: true + items: + type: object + additionalProperties: true + spiloFSGroup: + type: integer + standby: + type: object + required: + - s3_wal_path + properties: + s3_wal_path: + type: string + teamId: + type: string + tolerations: + type: array + items: + type: object + required: + - key + - operator + - effect + properties: + key: + type: string + operator: + type: string + enum: + - Equal + - Exists + value: + type: string + effect: + type: string + enum: + - NoExecute + - NoSchedule + - PreferNoSchedule + tolerationSeconds: + type: integer + useLoadBalancer: # deprecated + type: boolean + users: + type: object + additionalProperties: + type: array + nullable: true + description: "Role flags specified here must not contradict each other" + items: + type: string + enum: + - bypassrls + - BYPASSRLS + - nobypassrls + - NOBYPASSRLS + - createdb + - CREATEDB + - nocreatedb + - NOCREATEDB + - createrole + - CREATEROLE + - nocreaterole + - NOCREATEROLE + - inherit + - INHERIT + - noinherit + - NOINHERIT + - login + - LOGIN + - nologin + - NOLOGIN + - replication + - REPLICATION + - noreplication + - NOREPLICATION + - superuser + - SUPERUSER + - nosuperuser + - NOSUPERUSER + volume: + type: object + required: + - size + properties: + size: + type: string + pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' + # Note: the value specified here must not be zero. + storageClass: + type: string + subPath: + type: string diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index 50833db26..9ee76103f 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -1,7 +1,7 @@ package v1 import ( - "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do" + acidzalando "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -103,7 +103,902 @@ var OperatorConfigCRDResourceColumns = []apiextv1beta1.CustomResourceColumnDefin }, } -func buildCRD(name, kind, plural, short string, columns []apiextv1beta1.CustomResourceColumnDefinition) *apiextv1beta1.CustomResourceDefinition { +var min0 = 0.0 +var min1 = 1.0 +var minDisable = -1.0 + +// PostgresCRDResourceValidation to check applied manifest parameters +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"`), + }, + }, + }, + "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, + }, + }, + }, + }, + "initContainers": { + Type: "array", + Items: &apiextv1beta1.JSONSchemaPropsOrArray{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Allows: true, + }, + }, + }, + }, + "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"`), + }, + }, + }, + "parameters": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + }, + }, + "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"`), + }, + }, + }, + "value": { + Type: "string", + }, + "effect": { + Type: "string", + Enum: []apiextv1beta1.JSON{ + { + Raw: []byte(`"NoExecute"`), + }, + { + Raw: []byte(`"NoSchedule"`), + }, + { + Raw: []byte(`"PreferNoSchedule"`), + }, + }, + }, + "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", + }, + }, + }, + }, + }, + }, + }, +} + +// OperatorConfigCRDResourceValidation to check applied manifest parameters +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"`), + }, + }, + }, + "configuration": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "docker_image": { + Type: "string", + }, + "enable_crd_validation": { + Type: "boolean", + }, + "enable_shm_volume": { + Type: "boolean", + }, + "etcd_host": { + 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", + }, + }, + }, + "workers": { + Type: "integer", + Minimum: &min1, + }, + "users": { + Type: "object", + Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "replication_username": { + Type: "string", + }, + "super_username": { + 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", + }, + }, + }, + "cluster_name_label": { + Type: "string", + }, + "custom_pod_annotations": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + 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", + }, + }, + }, + "node_readiness_label": { + 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"`), + }, + }, + }, + "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", + }, + }, + }, + "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", + }, + }, + }, + "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", + }, + "logical_backup_s3_endpoint": { + Type: "string", + }, + "logical_backup_s3_sse": { + Type: "string", + }, + "logical_backup_s3_access_key_id": { + Type: "string", + }, + "logical_backup_s3_secret_access_key": { + 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", + }, + }, + }, + "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", + }, + }, + }, + "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": { + 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", + }, + }, + }, + }, + }, + }, + }, +} + +func buildCRD(name, kind, plural, short string, columns []apiextv1beta1.CustomResourceColumnDefinition, validation apiextv1beta1.CustomResourceValidation) *apiextv1beta1.CustomResourceDefinition { return &apiextv1beta1.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -121,24 +1016,39 @@ func buildCRD(name, kind, plural, short string, columns []apiextv1beta1.CustomRe Status: &apiextv1beta1.CustomResourceSubresourceStatus{}, }, AdditionalPrinterColumns: columns, + 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) + PostgresCRDResourceColumns, + 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) + OperatorConfigCRDResourceColumns, + 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/apis/acid.zalan.do/v1/zz_generated.deepcopy.go b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go index 793f236a5..433d37f87 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -216,6 +216,11 @@ func (in *OperatorConfiguration) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData) { *out = *in + if in.EnableCRDValidation != nil { + in, out := &in.EnableCRDValidation, &out.EnableCRDValidation + *out = new(bool) + **out = **in + } if in.ShmVolume != nil { in, out := &in.ShmVolume, &out.ShmVolume *out = new(bool) 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 diff --git a/run_operator_locally.sh b/run_operator_locally.sh index f5044dc14..9e3e082da 100755 --- a/run_operator_locally.sh +++ b/run_operator_locally.sh @@ -98,7 +98,7 @@ function build_operator_binary(){ # redirecting stderr greatly reduces non-informative output during normal builds echo "Build operator binary (stderr redirected to /dev/null)..." - make clean tools deps local test > /dev/null 2>&1 + make clean deps local test > /dev/null 2>&1 } From 551564011139d5a6cb9f635d091b2b54f56f125d Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Thu, 28 Nov 2019 17:39:25 +0100 Subject: [PATCH 10/21] install kind as GO module (#742) * install kind as GO modules * no need to set KIND_PATH --- .gitignore | 3 + e2e/Makefile | 6 +- e2e/run.sh | 14 ++-- go.mod | 20 ++++-- go.sum | 194 ++++++++++++++++++++++++++++++++++++++------------- 5 files changed, 171 insertions(+), 66 deletions(-) diff --git a/.gitignore b/.gitignore index 34d526578..991fe754f 100644 --- a/.gitignore +++ b/.gitignore @@ -86,6 +86,9 @@ coverage.xml .hypothesis/ .pytest_cache/ +# e2e tests +e2e/manifests + # Translations *.mo *.pot diff --git a/e2e/Makefile b/e2e/Makefile index ab19539f8..77059f3eb 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -23,7 +23,6 @@ ifndef GOPATH GOPATH := $(HOME)/go endif -KIND_PATH := $(GOPATH)/bin PATH := $(GOPATH)/bin:$(PATH) default: tools @@ -43,10 +42,7 @@ push: docker tools: docker # install pinned version of 'kind' - # leave the name as is to avoid overwriting official binary named `kind` - wget https://github.com/kubernetes-sigs/kind/releases/download/v0.5.1/kind-linux-amd64 - chmod +x kind-linux-amd64 - mv kind-linux-amd64 $(KIND_PATH) + GO111MODULE=on go get sigs.k8s.io/kind@v0.5.1 test: ./run.sh diff --git a/e2e/run.sh b/e2e/run.sh index 237960b89..c7825bfd3 100755 --- a/e2e/run.sh +++ b/e2e/run.sh @@ -30,15 +30,15 @@ function pull_images(){ function start_kind(){ # avoid interference with previous test runs - if [[ $(kind-linux-amd64 get clusters | grep "^${cluster_name}*") != "" ]] + if [[ $(kind get clusters | grep "^${cluster_name}*") != "" ]] then - kind-linux-amd64 delete cluster --name ${cluster_name} + kind delete cluster --name ${cluster_name} fi - kind-linux-amd64 create cluster --name ${cluster_name} --config kind-cluster-postgres-operator-e2e-tests.yaml - kind-linux-amd64 load docker-image "${operator_image}" --name ${cluster_name} - kind-linux-amd64 load docker-image "${e2e_test_image}" --name ${cluster_name} - KUBECONFIG="$(kind-linux-amd64 get kubeconfig-path --name=${cluster_name})" + kind create cluster --name ${cluster_name} --config kind-cluster-postgres-operator-e2e-tests.yaml + kind load docker-image "${operator_image}" --name ${cluster_name} + kind load docker-image "${e2e_test_image}" --name ${cluster_name} + KUBECONFIG="$(kind get kubeconfig-path --name=${cluster_name})" export KUBECONFIG } @@ -58,7 +58,7 @@ function run_tests(){ function clean_up(){ unset KUBECONFIG - kind-linux-amd64 delete cluster --name ${cluster_name} + kind delete cluster --name ${cluster_name} rm -rf ${kubeconfig_path} } diff --git a/go.mod b/go.mod index 8efd4939d..9012721d1 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,22 @@ go 1.12 require ( github.com/aws/aws-sdk-go v1.25.1 + github.com/emicklei/go-restful v2.9.6+incompatible // indirect + github.com/evanphx/json-patch v4.5.0+incompatible // indirect + github.com/googleapis/gnostic v0.3.0 // indirect github.com/imdario/mergo v0.3.7 // indirect github.com/lib/pq v1.2.0 github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d github.com/sirupsen/logrus v1.4.2 - gopkg.in/yaml.v2 v2.2.2 - k8s.io/api v0.0.0-20190927115716-5d581ce610b0 - k8s.io/apiextensions-apiserver v0.0.0-20190927042040-728319705b32 - k8s.io/apimachinery v0.0.0-20190927035529-0104e33c351d - k8s.io/client-go v0.0.0-20190926235751-95884bf844a9 - k8s.io/code-generator v0.0.0-20190927075303-016f2b3d74d0 + golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c // indirect + golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 // indirect + golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect + golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + gopkg.in/yaml.v2 v2.2.5 + k8s.io/api v0.0.0-20191121015604-11707872ac1c + k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8 + k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a + k8s.io/client-go v11.0.0+incompatible + k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e ) diff --git a/go.sum b/go.sum index 8995710ba..e7a0a15e3 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,7 @@ github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxB github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= @@ -19,8 +20,10 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -28,18 +31,21 @@ github.com/aws/aws-sdk-go v1.25.1 h1:d7zDXFT2Tgq/yw7Wku49+lKisE8Xc85erb+8PlE/Shk github.com/aws/aws-sdk-go v1.25.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -47,16 +53,27 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w= +github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -66,6 +83,7 @@ github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70t github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= @@ -74,37 +92,51 @@ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwds github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -112,7 +144,10 @@ github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -122,20 +157,25 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= +github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= @@ -148,13 +188,17 @@ github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBv github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= @@ -168,6 +212,12 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -181,41 +231,56 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d h1:LznySqW8MqVeFh+pW6rOkFdld9QQ7jRydBKKM6jyPVI= github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d/go.mod h1:u3hJ0kqCQu/cPpsu3RbCOPZ0d7V3IjPjv1adNRleM9I= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -223,14 +288,24 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -238,8 +313,13 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495 h1:I6A9Ag9FpEKOjcKrRNjQkPHawoXIhKyTGfvvjFAiiAk= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -253,14 +333,19 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 h1:e6HwijUxhDe+hPNjZQQn9bA5PW3vNmnN64U2ZW759Lk= +golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= @@ -274,6 +359,7 @@ golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -284,17 +370,25 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= +golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -302,11 +396,15 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f h1:3MlESg/jvTr87F4ttA/q4B+uhe/q6qleC9/DP+IwQmY= +golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485 h1:OB/uP/Puiu5vS5QMRPrXCDWUPb+kt8f1KW8oQzFejQw= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e h1:jRyg0XfpwWlhEV8mDfdNGBeSJM2fuyh9Yjrnd8kF2Ts= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -318,65 +416,65 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48= -k8s.io/api v0.0.0-20190925180651-d58b53da08f5/go.mod h1:blPYY5r6fKug8SVOnjDtFAlzZzInCRL9NNls66SFhFI= -k8s.io/api v0.0.0-20190927115716-5d581ce610b0 h1:fwx2jAKNlXBQ8uiB3RNN5hVU/nEJTEBg/CfxoXEYri4= -k8s.io/api v0.0.0-20190927115716-5d581ce610b0/go.mod h1:l2ZHS8QbgqodGx7yrYsOSwIxOR76BpGiW1OywXo9PFI= -k8s.io/apiextensions-apiserver v0.0.0-20190927042040-728319705b32 h1:ss1T2mi6o+ji42DAoFxrophF9dysSKUXyq6fTmCMvFI= -k8s.io/apiextensions-apiserver v0.0.0-20190927042040-728319705b32/go.mod h1:SMmFyjBO4fGs1v/nrTzNbhyg4PEGUH+h3ilWsi90RPk= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= -k8s.io/apimachinery v0.0.0-20190923155427-ec87dd743e08/go.mod h1:grJJH0hgilA2pYoUiJcPu2EDUal95NTq1vpxxvMLSu8= -k8s.io/apimachinery v0.0.0-20190925235427-62598f38f24e/go.mod h1:grJJH0hgilA2pYoUiJcPu2EDUal95NTq1vpxxvMLSu8= -k8s.io/apimachinery v0.0.0-20190927035529-0104e33c351d h1:oYLB5Nk2IOm17BHdatnaWAgzNGzq/5dlWy7Bzo5Htdc= -k8s.io/apimachinery v0.0.0-20190927035529-0104e33c351d/go.mod h1:grJJH0hgilA2pYoUiJcPu2EDUal95NTq1vpxxvMLSu8= -k8s.io/apiserver v0.0.0-20190927000204-dd401ce564d5/go.mod h1:oXS8tPljvXCBPjzDnAM7xnx26pzwFT+oIqIUCmG8Pj8= -k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90 h1:mLmhKUm1X+pXu0zXMEzNsOF5E2kKFGe5o6BZBIIqA6A= -k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk= -k8s.io/client-go v0.0.0-20190925235746-07054768d98d/go.mod h1:KumMj5rt+3qCPy5LJipGocsmMx6RW8vdDAs8QNK6jvU= -k8s.io/client-go v0.0.0-20190926235751-95884bf844a9 h1:YpRGAa4i68p7SGIuJAaZgE7oumAMxzsTux2gTur2eMM= -k8s.io/client-go v0.0.0-20190926235751-95884bf844a9/go.mod h1:KumMj5rt+3qCPy5LJipGocsmMx6RW8vdDAs8QNK6jvU= +k8s.io/api v0.0.0-20191121015604-11707872ac1c h1:Z87my3sF4WhG0OMxzARkWY/IKBtOr+MhXZAb4ts6qFc= +k8s.io/api v0.0.0-20191121015604-11707872ac1c/go.mod h1:R/s4gKT0V/cWEnbQa9taNRJNbWUK57/Dx6cPj6MD3A0= +k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8 h1:SrFLwOURsuwzuCi0zJdaBbPF31AcV9JUwpwIVosnnE4= +k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8/go.mod h1:NMIy5Wa/or8CsLhYRleOp9CWAHVdcWpzT6Ufx1SNVjA= +k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a h1:9V03T5lHv/iF4fSgvMCd+iB86AgEgmzLpheMqIJy7hs= +k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apiserver v0.0.0-20191121020624-6eed2f5a3289/go.mod h1:7P+0qMKoaggchirHLUSCVD22ohdkjN19+qQOKcAdfbI= +k8s.io/client-go v0.0.0-20191121015835-571c0ef67034 h1:+/ppGIi1rJThJAz/xJSSOuD82gb6E5jRv2305MSznxQ= +k8s.io/client-go v0.0.0-20191121015835-571c0ef67034/go.mod h1:Adhj+OyDRsEXTnL9BfL7xbLWGWMCqGLWpMqGHkZI4J8= k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o= k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/code-generator v0.0.0-20190925195306-32dfb485ddce/go.mod h1:4MfOrxyyZxxCuenwsdaJRtoSnOP5T13jE2LRYPZ6KeY= -k8s.io/code-generator v0.0.0-20190927075303-016f2b3d74d0 h1:rhwEVFHoBm42V0b7yN9SUdbWzfCVndLzRV8YGIi0uWY= -k8s.io/code-generator v0.0.0-20190927075303-016f2b3d74d0/go.mod h1:4MfOrxyyZxxCuenwsdaJRtoSnOP5T13jE2LRYPZ6KeY= -k8s.io/component-base v0.0.0-20190926082537-804254d56004/go.mod h1:+sedDd0Yj/9lFSZjan8FdX4Jednr2we+Q0ZDeicbKSc= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e h1:HB9Zu5ZUvJfNpLiTPhz+CebVKV8C39qTBMQkAgAZLNw= +k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.0.0-20191121020327-771114ba3383/go.mod h1:tv9ITs6VEFWkF+kHwY4GiFvDr9vUGKJ4X/8+Z+oqVLk= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKOxmGeKRbsXVmqYM= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf h1:EYm5AW/UUDbnmnI+gK0TJDVK9qPLhM+sRHYanNKw0EQ= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20190920012459-5008bf6f8cd6 h1:rfepARh/ECp66dk9TTmT//1PBkHffjnxhdOrgH4m+eA= -k8s.io/utils v0.0.0-20190920012459-5008bf6f8cd6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= From 11c2e815f7740d2905d6088d23f1318b4b9aebef Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Mon, 2 Dec 2019 15:27:47 +0100 Subject: [PATCH 11/21] include status subresource in validation (#744) * include status subresource in validation --- .../crds/operatorconfigurations.yaml | 4 ++++ manifests/operatorconfiguration.crd.yaml | 4 ++++ manifests/postgresql.crd.yaml | 4 ++++ pkg/apis/acid.zalan.do/v1/crds.go | 16 ++++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index ff92bc064..f50180c2a 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -298,3 +298,7 @@ spec: pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' scalyr_server_url: type: string + status: + type: object + additionalProperties: + type: string diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index 753415a15..7e9c03509 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -274,3 +274,7 @@ spec: pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' scalyr_server_url: type: string + status: + type: object + additionalProperties: + type: string diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index 4a578b324..d563962bb 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -325,3 +325,7 @@ spec: type: string subPath: type: string + status: + type: object + additionalProperties: + type: string diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index 9ee76103f..35a8227b0 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -578,6 +578,14 @@ var PostgresCRDResourceValidation = apiextv1beta1.CustomResourceValidation{ }, }, }, + "status": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, }, }, } @@ -994,6 +1002,14 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation }, }, }, + "status": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, }, }, } From 7037974d4812d9d80dba134bef1082e6f3723c20 Mon Sep 17 00:00:00 2001 From: Frederik Wagner <55986520+fwagner-smf@users.noreply.github.com> Date: Wed, 4 Dec 2019 17:47:05 +0100 Subject: [PATCH 12/21] fix s3 bucket endpoint/sse configuration in logical backup dump.sh (#750) --- docker/logical-backup/dump.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/logical-backup/dump.sh b/docker/logical-backup/dump.sh index 5c2e478a9..78217322b 100755 --- a/docker/logical-backup/dump.sh +++ b/docker/logical-backup/dump.sh @@ -41,8 +41,8 @@ function aws_upload { args=() [[ ! -z "$EXPECTED_SIZE" ]] && args+=("--expected-size=$EXPECTED_SIZE") - [[ ! -z "$LOGICAL_BACKUP_S3_ENDPOINT" ]] && args+=("--endpoint-url=\"$LOGICAL_BACKUP_S3_ENDPOINT\"") - [[ ! "$LOGICAL_BACKUP_S3_SSE" == "" ]] && args+=("--sse=\"$LOGICAL_BACKUP_S3_SSE\"") + [[ ! -z "$LOGICAL_BACKUP_S3_ENDPOINT" ]] && args+=("--endpoint-url=$LOGICAL_BACKUP_S3_ENDPOINT") + [[ ! "$LOGICAL_BACKUP_S3_SSE" == "" ]] && args+=("--sse=$LOGICAL_BACKUP_S3_SSE") aws s3 cp - "$PATH_TO_BACKUP" "${args[@]//\'/}" --debug } From 076116589d88b6bf2d2788da1800c31b726bdea6 Mon Sep 17 00:00:00 2001 From: zimbatm Date: Tue, 10 Dec 2019 13:54:12 +0000 Subject: [PATCH 13/21] hack: update shebang (#755) Make the shebang work on NixOS and other non-Ubuntu systems. --- hack/update-codegen.sh | 2 +- hack/verify-codegen.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 4625f7c9a..280da9385 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -o errexit set -o nounset diff --git a/hack/verify-codegen.sh b/hack/verify-codegen.sh index 904586d05..68710015e 100755 --- a/hack/verify-codegen.sh +++ b/hack/verify-codegen.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -o errexit set -o nounset From 107334fe71af5fa4cc7df1b2af7043f3cf28bc24 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Tue, 10 Dec 2019 15:45:54 +0100 Subject: [PATCH 14/21] Add global option to enable/disable init containers and sidecars (#478) * Add global option to enable/disable init containers and sidecars * update dependencies --- .../crds/operatorconfigurations.yaml | 4 ++ charts/postgres-operator/values-crd.yaml | 4 ++ charts/postgres-operator/values.yaml | 6 ++- docs/reference/operator_parameters.md | 14 ++++-- docs/user.md | 8 ++++ e2e/tests/test_e2e.py | 17 ++++--- go.mod | 14 +++--- go.sum | 44 +++++++++++-------- manifests/configmap.yaml | 2 + manifests/operatorconfiguration.crd.yaml | 4 ++ ...gresql-operator-default-configuration.yaml | 6 ++- pkg/apis/acid.zalan.do/v1/crds.go | 6 +++ .../v1/operator_configuration_type.go | 2 + .../acid.zalan.do/v1/zz_generated.deepcopy.go | 10 +++++ pkg/cluster/k8sres.go | 23 +++++++--- pkg/cluster/k8sres_test.go | 2 +- pkg/cluster/resources.go | 11 +++++ pkg/cluster/types.go | 2 +- pkg/controller/operator_config.go | 2 + pkg/controller/util_test.go | 2 +- pkg/util/config/config.go | 2 + 21 files changed, 138 insertions(+), 47 deletions(-) diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index f50180c2a..d50a2b431 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -107,10 +107,14 @@ spec: type: object additionalProperties: type: string + enable_init_containers: + type: boolean enable_pod_antiaffinity: type: boolean enable_pod_disruption_budget: type: boolean + enable_sidecars: + type: boolean infrastructure_roles_secret_name: type: string inherited_labels: diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index c6f11e493..40cccfb54 100644 --- a/charts/postgres-operator/values-crd.yaml +++ b/charts/postgres-operator/values-crd.yaml @@ -63,10 +63,14 @@ configKubernetes: # keya: valuea # keyb: valueb + # enables initContainers to run actions before Spilo is started + enable_init_containers: true # toggles pod anti affinity on the Postgres pods enable_pod_antiaffinity: false # toggles PDB to set to MinAvailabe 0 or 1 enable_pod_disruption_budget: true + # enables sidecar containers to run alongside Spilo in the same pod + enable_sidecars: true # name of the secret containing infrastructure roles names and passwords # infrastructure_roles_secret_name: postgresql-infrastructure-roles diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index ae9e06fe9..826862c4a 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -57,12 +57,16 @@ configKubernetes: # label assigned to Kubernetes objects created by the operator cluster_name_label: version # annotations attached to each database pod - # custom_pod_annotations: keya:valuea,keyb:valueb + # custom_pod_annotations: "keya:valuea,keyb:valueb" + # enables initContainers to run actions before Spilo is started + enable_init_containers: "true" # toggles pod anti affinity on the Postgres pods enable_pod_antiaffinity: "false" # toggles PDB to set to MinAvailabe 0 or 1 enable_pod_disruption_budget: "true" + # enables sidecar containers to run alongside Spilo in the same pod + enable_sidecars: "true" # name of the secret containing infrastructure roles names and passwords # infrastructure_roles_secret_name: postgresql-infrastructure-roles diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index e16282fd2..3de4a5be4 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -87,9 +87,9 @@ Those are top-level keys, containing both leaf keys and groups. repository](https://github.com/zalando/spilo). * **sidecar_docker_images** - a map of sidecar names to docker images for the containers to run alongside - Spilo. In case of the name conflict with the definition in the cluster - manifest the cluster-specific one is preferred. + a map of sidecar names to docker images to run with Spilo. In case of the name + conflict with the definition in the cluster manifest the cluster-specific one + is preferred. * **enable_shm_volume** Instruct operator to start any new database pod without limitations on shm @@ -196,6 +196,14 @@ configuration they are grouped under the `kubernetes` key. [admin docs](../administrator.md#pod-disruption-budget) for more information. Default is true. +* **enable_init_containers** + global option to allow for creating init containers to run actions before + Spilo is started. Default is true. + +* **enable_sidecars** + global option to allow for creating sidecar containers to run alongside Spilo + on the same pod. Default is true. + * **secret_name_template** a template for the name of the database user secrets generated by the operator. `{username}` is replaced with name of the secret, `{cluster}` with diff --git a/docs/user.md b/docs/user.md index ee8e7183c..272defe08 100644 --- a/docs/user.md +++ b/docs/user.md @@ -350,6 +350,10 @@ variables are always passed to sidecars: The PostgreSQL volume is shared with sidecars and is mounted at `/home/postgres/pgdata`. +**Note**: The operator will not create a cluster if sidecar containers are +specified but globally disabled in the configuration. The `enable_sidecars` +option must be set to `true`. + ## InitContainers Support Each cluster can specify arbitrary init containers to run. These containers can @@ -374,6 +378,10 @@ spec: `initContainers` accepts full `v1.Container` definition. +**Note**: The operator will not create a cluster if `initContainers` are +specified but globally disabled in the configuration. The +`enable_init_containers` option must be set to `true`. + ## Increase volume size PostgreSQL operator supports statefulset volume resize if you're using the diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 52aa0549a..88a7f1f34 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -182,17 +182,12 @@ class EndToEndTestCase(unittest.TestCase): # update the cluster-wide image of the logical backup pod image = "test-image-name" - config_map_patch = { + patch_logical_backup_image = { "data": { "logical_backup_docker_image": image, } } - k8s.api.core_v1.patch_namespaced_config_map("postgres-operator", "default", config_map_patch) - - operator_pod = k8s.api.core_v1.list_namespaced_pod( - 'default', label_selector="name=postgres-operator").items[0].metadata.name - k8s.api.core_v1.delete_namespaced_pod(operator_pod, "default") # restart reloads the conf - k8s.wait_for_operator_pod_start() + k8s.update_config(patch_logical_backup_image) jobs = k8s.get_logical_backup_job().items actual_image = jobs[0].spec.job_template.spec.template.spec.containers[0].image @@ -319,6 +314,14 @@ class K8s: def wait_for_logical_backup_job_creation(self): self.wait_for_logical_backup_job(expected_num_of_jobs=1) + def update_config(self, config_map_patch): + self.api.core_v1.patch_namespaced_config_map("postgres-operator", "default", config_map_patch) + + operator_pod = self.api.core_v1.list_namespaced_pod( + 'default', label_selector="name=postgres-operator").items[0].metadata.name + self.api.core_v1.delete_namespaced_pod(operator_pod, "default") # restart reloads the conf + self.wait_for_operator_pod_start() + def create_with_kubectl(self, path): subprocess.run(["kubectl", "create", "-f", path]) diff --git a/go.mod b/go.mod index 9012721d1..b8c7b1615 100644 --- a/go.mod +++ b/go.mod @@ -3,23 +3,21 @@ module github.com/zalando/postgres-operator go 1.12 require ( - github.com/aws/aws-sdk-go v1.25.1 - github.com/emicklei/go-restful v2.9.6+incompatible // indirect - github.com/evanphx/json-patch v4.5.0+incompatible // indirect - github.com/googleapis/gnostic v0.3.0 // indirect - github.com/imdario/mergo v0.3.7 // indirect + github.com/aws/aws-sdk-go v1.25.44 + github.com/imdario/mergo v0.3.8 // indirect github.com/lib/pq v1.2.0 github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d github.com/sirupsen/logrus v1.4.2 - golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c // indirect + golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e // indirect golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 // indirect golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect - golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f // indirect + golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect - gopkg.in/yaml.v2 v2.2.5 + gopkg.in/yaml.v2 v2.2.4 k8s.io/api v0.0.0-20191121015604-11707872ac1c k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8 k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a k8s.io/client-go v11.0.0+incompatible k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e + sigs.k8s.io/kind v0.5.1 // indirect ) diff --git a/go.sum b/go.sum index e7a0a15e3..c7f7be037 100644 --- a/go.sum +++ b/go.sum @@ -27,8 +27,8 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.25.1 h1:d7zDXFT2Tgq/yw7Wku49+lKisE8Xc85erb+8PlE/Shk= -github.com/aws/aws-sdk-go v1.25.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.44 h1:n9ahFoiyn66smjF34hYr3tb6/ZdBcLuFz7BCDhHyJ7I= +github.com/aws/aws-sdk-go v1.25.44/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -90,14 +90,12 @@ github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= @@ -112,7 +110,6 @@ github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29g github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= @@ -123,7 +120,6 @@ github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -160,6 +156,7 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= @@ -177,9 +174,10 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= -github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -210,8 +208,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= @@ -237,13 +235,14 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -265,12 +264,14 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -311,12 +312,11 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4= -golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e h1:egKlR8l7Nu9vHGWbcUV8lqR4987UfUbBd7GbhqGzNYU= +golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495 h1:I6A9Ag9FpEKOjcKrRNjQkPHawoXIhKyTGfvvjFAiiAk= @@ -368,8 +368,8 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190621203818-d432491b9138/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -398,8 +398,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f h1:3MlESg/jvTr87F4ttA/q4B+uhe/q6qleC9/DP+IwQmY= -golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d h1:/iIZNFGxc/a7C3yWjGcnboV+Tkc7mxr+p6fDztwoxuM= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485 h1:OB/uP/Puiu5vS5QMRPrXCDWUPb+kt8f1KW8oQzFejQw= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= @@ -438,16 +438,18 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.0.0-20190313235455-40a48860b5ab/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.0.0-20191121015604-11707872ac1c h1:Z87my3sF4WhG0OMxzARkWY/IKBtOr+MhXZAb4ts6qFc= k8s.io/api v0.0.0-20191121015604-11707872ac1c/go.mod h1:R/s4gKT0V/cWEnbQa9taNRJNbWUK57/Dx6cPj6MD3A0= k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8 h1:SrFLwOURsuwzuCi0zJdaBbPF31AcV9JUwpwIVosnnE4= k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8/go.mod h1:NMIy5Wa/or8CsLhYRleOp9CWAHVdcWpzT6Ufx1SNVjA= +k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a h1:9V03T5lHv/iF4fSgvMCd+iB86AgEgmzLpheMqIJy7hs= k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apiserver v0.0.0-20191121020624-6eed2f5a3289/go.mod h1:7P+0qMKoaggchirHLUSCVD22ohdkjN19+qQOKcAdfbI= @@ -463,8 +465,10 @@ k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKO k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= @@ -474,6 +478,10 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +sigs.k8s.io/kind v0.5.1 h1:BYnHEJ9DC+0Yjlyyehqd3xnKtEmFdLKU8QxqOqvQzdw= +sigs.k8s.io/kind v0.5.1/go.mod h1:L+Kcoo83/D1+ryU5P2VFbvYm0oqbkJn9zTZq0KNxW68= +sigs.k8s.io/kustomize/v3 v3.1.1-0.20190821175718-4b67a6de1296 h1:iQaIG5Dq+3qSiaFrJ/l/0MjjxKmdwyVNpKRYJwUe/+0= +sigs.k8s.io/kustomize/v3 v3.1.1-0.20190821175718-4b67a6de1296/go.mod h1:ztX4zYc/QIww3gSripwF7TBOarBTm5BvyAMem0kCzOE= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 59d3abfde..5a975c68f 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -23,11 +23,13 @@ data: # enable_admin_role_for_users: "true" # enable_crd_validation: "true" # enable_database_access: "true" + # enable_init_containers: "true" enable_master_load_balancer: "false" # enable_pod_antiaffinity: "false" # enable_pod_disruption_budget: "true" enable_replica_load_balancer: "false" # enable_shm_volume: "true" + # enable_sidecars: "true" # enable_team_superuser: "false" enable_teams_api: "false" # etcd_host: "" diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index 7e9c03509..bed892dc8 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -83,10 +83,14 @@ spec: type: object additionalProperties: type: string + enable_init_containers: + type: boolean enable_pod_antiaffinity: type: boolean enable_pod_disruption_budget: type: boolean + enable_sidecars: + type: boolean infrastructure_roles_secret_name: type: string inherited_labels: diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index 7a867d5df..84e12b4ee 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -26,14 +26,16 @@ configuration: # custom_pod_annotations: # keya: valuea # keyb: valueb + enable_init_containers: true enable_pod_antiaffinity: false enable_pod_disruption_budget: true - # infrastructure_roles_secret_name: postgresql-infrastructure-roles + enable_sidecars: true + # infrastructure_roles_secret_name: "postgresql-infrastructure-roles" # inherited_labels: # - application # - environment # node_readiness_label: - # status: ready + # status: ready oauth_token_secret_name: postgresql-operator pdb_name_format: "postgres-{cluster}-pdb" pod_antiaffinity_topology_key: "kubernetes.io/hostname" diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index 35a8227b0..2a25c374f 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -694,12 +694,18 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation }, }, }, + "enable_init_containers": { + Type: "boolean", + }, "enable_pod_antiaffinity": { Type: "boolean", }, "enable_pod_disruption_budget": { Type: "boolean", }, + "enable_sidecars": { + Type: "boolean", + }, "infrastructure_roles_secret_name": { Type: "string", }, 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 d97852b2f..f76790ad5 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -50,6 +50,8 @@ type KubernetesMetaConfiguration struct { WatchedNamespace string `json:"watched_namespace,omitempty"` PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"` EnablePodDisruptionBudget *bool `json:"enable_pod_disruption_budget,omitempty"` + EnableInitContainers *bool `json:"enable_init_containers,omitempty"` + EnableSidecars *bool `json:"enable_sidecars,omitempty"` SecretNameTemplate config.StringTemplate `json:"secret_name_template,omitempty"` ClusterDomain string `json:"cluster_domain"` OAuthTokenSecretName spec.NamespacedName `json:"oauth_token_secret_name,omitempty"` diff --git a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go index 433d37f87..16f5a9d67 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -81,6 +81,16 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura *out = new(bool) **out = **in } + if in.EnableInitContainers != nil { + in, out := &in.EnableInitContainers, &out.EnableInitContainers + *out = new(bool) + **out = **in + } + if in.EnableSidecars != nil { + in, out := &in.EnableSidecars, &out.EnableSidecars + *out = new(bool) + **out = **in + } out.OAuthTokenSecretName = in.OAuthTokenSecretName out.InfrastructureRolesSecretName = in.InfrastructureRolesSecretName if in.ClusterLabels != nil { diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 95e83454f..73be712ca 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -720,6 +720,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef var ( err error + initContainers []v1.Container sidecarContainers []v1.Container podTemplate *v1.PodTemplateSpec volumeClaimTemplate *v1.PersistentVolumeClaim @@ -786,6 +787,13 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef return nil, fmt.Errorf("could not generate resource requirements: %v", err) } + if spec.InitContainers != nil && len(spec.InitContainers) > 0 { + if c.OpConfig.EnableInitContainers != nil && !(*c.OpConfig.EnableInitContainers) { + c.logger.Warningf("initContainers specified but disabled in configuration - next statefulset creation would fail") + } + initContainers = spec.InitContainers + } + customPodEnvVarsList := make([]v1.EnvVar, 0) if c.OpConfig.PodEnvironmentConfigMap != "" { @@ -872,9 +880,14 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef } // generate sidecar containers - if sidecarContainers, err = generateSidecarContainers(sideCars, volumeMounts, defaultResources, - c.OpConfig.SuperUsername, c.credentialSecretName(c.OpConfig.SuperUsername), c.logger); err != nil { - return nil, fmt.Errorf("could not generate sidecar containers: %v", err) + if sideCars != nil && len(sideCars) > 0 { + if c.OpConfig.EnableSidecars != nil && !(*c.OpConfig.EnableSidecars) { + c.logger.Warningf("sidecars specified but disabled in configuration - next statefulset creation would fail") + } + if sidecarContainers, err = generateSidecarContainers(sideCars, volumeMounts, defaultResources, + c.OpConfig.SuperUsername, c.credentialSecretName(c.OpConfig.SuperUsername), c.logger); err != nil { + return nil, fmt.Errorf("could not generate sidecar containers: %v", err) + } } tolerationSpec := tolerations(&spec.Tolerations, c.OpConfig.PodToleration) @@ -894,7 +907,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef c.labelsSet(true), annotations, spiloContainer, - spec.InitContainers, + initContainers, sidecarContainers, &tolerationSpec, effectiveFSGroup, @@ -1412,7 +1425,7 @@ func (c *Cluster) generatePodDisruptionBudget() *policybeta1.PodDisruptionBudget pdbEnabled := c.OpConfig.EnablePodDisruptionBudget // if PodDisruptionBudget is disabled or if there are no DB pods, set the budget to 0. - if (pdbEnabled != nil && !*pdbEnabled) || c.Spec.NumberOfInstances <= 0 { + if (pdbEnabled != nil && !(*pdbEnabled)) || c.Spec.NumberOfInstances <= 0 { minAvailable = intstr.FromInt(0) } diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index 5b206f760..e8fe05456 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -3,7 +3,7 @@ package cluster import ( "reflect" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "testing" diff --git a/pkg/cluster/resources.go b/pkg/cluster/resources.go index 3e8f73916..c94a7bb46 100644 --- a/pkg/cluster/resources.go +++ b/pkg/cluster/resources.go @@ -65,6 +65,17 @@ func (c *Cluster) listResources() error { func (c *Cluster) createStatefulSet() (*appsv1.StatefulSet, error) { c.setProcessName("creating statefulset") + // check if it's allowed that spec contains initContainers + if c.Spec.InitContainers != nil && len(c.Spec.InitContainers) > 0 && + c.OpConfig.EnableInitContainers != nil && !(*c.OpConfig.EnableInitContainers) { + return nil, fmt.Errorf("initContainers specified but disabled in configuration") + } + // check if it's allowed that spec contains sidecars + if c.Spec.Sidecars != nil && len(c.Spec.Sidecars) > 0 && + c.OpConfig.EnableSidecars != nil && !(*c.OpConfig.EnableSidecars) { + return nil, fmt.Errorf("sidecar containers specified but disabled in configuration") + } + statefulSetSpec, err := c.generateStatefulSet(&c.Spec) if err != nil { return nil, fmt.Errorf("could not generate statefulset: %v", err) diff --git a/pkg/cluster/types.go b/pkg/cluster/types.go index afdc7376e..138b7015c 100644 --- a/pkg/cluster/types.go +++ b/pkg/cluster/types.go @@ -5,7 +5,7 @@ import ( acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" appsv1 "k8s.io/api/apps/v1" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" policybeta1 "k8s.io/api/policy/v1beta1" "k8s.io/apimachinery/pkg/types" ) diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 9bed7ed13..56ba91d02 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -54,6 +54,8 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.WatchedNamespace = fromCRD.Kubernetes.WatchedNamespace result.PDBNameFormat = fromCRD.Kubernetes.PDBNameFormat result.EnablePodDisruptionBudget = fromCRD.Kubernetes.EnablePodDisruptionBudget + result.EnableInitContainers = fromCRD.Kubernetes.EnableInitContainers + result.EnableSidecars = fromCRD.Kubernetes.EnableSidecars result.SecretNameTemplate = fromCRD.Kubernetes.SecretNameTemplate result.OAuthTokenSecretName = fromCRD.Kubernetes.OAuthTokenSecretName result.InfrastructureRolesSecretName = fromCRD.Kubernetes.InfrastructureRolesSecretName diff --git a/pkg/controller/util_test.go b/pkg/controller/util_test.go index c9e16cbd9..a5d3c7ac5 100644 --- a/pkg/controller/util_test.go +++ b/pkg/controller/util_test.go @@ -9,7 +9,7 @@ import ( "github.com/zalando/postgres-operator/pkg/spec" "github.com/zalando/postgres-operator/pkg/util/k8sutil" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 52a0c4020..d46cba2b2 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -123,6 +123,8 @@ type Config struct { ReplicaDNSNameFormat StringTemplate `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"` PDBNameFormat StringTemplate `name:"pdb_name_format" default:"postgres-{cluster}-pdb"` EnablePodDisruptionBudget *bool `name:"enable_pod_disruption_budget" default:"true"` + EnableInitContainers *bool `name:"enable_init_containers" default:"true"` + EnableSidecars *bool `name:"enable_sidecars" default:"true"` Workers uint32 `name:"workers" default:"4"` APIPort int `name:"api_port" default:"8080"` RingLogLines int `name:"ring_log_lines" default:"100"` From 062843925686cd155c254ce86eb33522f3a4ba43 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Tue, 10 Dec 2019 16:30:57 +0100 Subject: [PATCH 15/21] fix cpu resource validation (#757) --- charts/postgres-operator/crds/postgresqls.yaml | 4 ++-- manifests/postgresql.crd.yaml | 4 ++-- pkg/apis/acid.zalan.do/v1/crds.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/postgres-operator/crds/postgresqls.yaml b/charts/postgres-operator/crds/postgresqls.yaml index a8c5f2954..198afe119 100644 --- a/charts/postgres-operator/crds/postgresqls.yaml +++ b/charts/postgres-operator/crds/postgresqls.yaml @@ -222,7 +222,7 @@ spec: # only the format of the given number. # # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu - pattern: '^(\d+m|\d+\.\d{1,3})$' + pattern: '^(\d+m|\d+(\.\d{1,3})?)$' # Note: the value specified here must not be zero or be lower # than the corresponding request. memory: @@ -253,7 +253,7 @@ spec: # only the format of the given number. # # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu - pattern: '^(\d+m|\d+\.\d{1,3})$' + pattern: '^(\d+m|\d+(\.\d{1,3})?)$' # Note: the value specified here must not be zero or be higher # than the corresponding limit. memory: diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index d563962bb..3b0f652ea 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -186,7 +186,7 @@ spec: # only the format of the given number. # # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu - pattern: '^(\d+m|\d+\.\d{1,3})$' + pattern: '^(\d+m|\d+(\.\d{1,3})?)$' # Note: the value specified here must not be zero or be lower # than the corresponding request. memory: @@ -217,7 +217,7 @@ spec: # only the format of the given number. # # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu - pattern: '^(\d+m|\d+\.\d{1,3})$' + pattern: '^(\d+m|\d+(\.\d{1,3})?)$' # Note: the value specified here must not be zero or be higher # than the corresponding limit. memory: diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index 2a25c374f..75704afde 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -356,7 +356,7 @@ var PostgresCRDResourceValidation = apiextv1beta1.CustomResourceValidation{ "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})$", + Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", }, "memory": { Type: "string", @@ -372,7 +372,7 @@ var PostgresCRDResourceValidation = apiextv1beta1.CustomResourceValidation{ "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})$", + Pattern: "^(\\d+m|\\d+(\\.\\d{1,3})?)$", }, "memory": { Type: "string", From cd110aabf48e3630483af7ca4b6647faed7f62e2 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Thu, 12 Dec 2019 16:43:55 +0100 Subject: [PATCH 16/21] Enforce minimum cpu and memory limits (#731) * add validation for PG resources and volume size * check resource requests also on UPDATE and SYNC + update docs * if cluster was running don't error on sync --- docs/user.md | 35 +++++++++++++++++-- manifests/standby-manifest.yaml | 2 +- pkg/cluster/cluster.go | 59 +++++++++++++++++++++++++++++++++ pkg/cluster/k8sres.go | 4 +-- pkg/cluster/sync.go | 11 ++++++ pkg/controller/controller.go | 4 +-- pkg/util/util.go | 8 ++--- pkg/util/util_test.go | 12 +++---- 8 files changed, 117 insertions(+), 18 deletions(-) diff --git a/docs/user.md b/docs/user.md index 272defe08..d9e92d5d6 100644 --- a/docs/user.md +++ b/docs/user.md @@ -30,7 +30,7 @@ spec: databases: foo: zalando postgresql: - version: "10" + version: "11" ``` Once you cloned the Postgres Operator [repository](https://github.com/zalando/postgres-operator) @@ -40,6 +40,9 @@ you can find this example also in the manifests folder: kubectl create -f manifests/minimal-postgres-manifest.yaml ``` +Note, that the minimum volume size to run the `postgresql` resource on Elastic +Block Storage (EBS) is `1Gi`. + ## Watch pods being created ```bash @@ -182,6 +185,32 @@ See [infrastructure roles secret](../manifests/infrastructure-roles.yaml) and [infrastructure roles configmap](../manifests/infrastructure-roles-configmap.yaml) for the examples. +## Resource definition + +The compute resources to be used for the Postgres containers in the pods can be +specified in the postgresql cluster manifest. + +```yaml +apiVersion: "acid.zalan.do/v1" +kind: postgresql +metadata: + name: acid-minimal-cluster +spec: + resources: + requests: + cpu: 10m + memory: 100Mi + limits: + cpu: 300m + memory: 300Mi +``` + +The minimum limit to properly run the `postgresql` resource is `256m` for `cpu` +and `256Mi` for `memory`. If a lower value is set in the manifest the operator +will cancel ADD or UPDATE events on this resource with an error. If no +resources are defined in the manifest the operator will obtain the configured +[default requests](reference/operator_parameters.md#kubernetes-resource-requests). + ## Use taints and tolerations for dedicated PostgreSQL nodes To ensure Postgres pods are running on nodes without any other application pods, @@ -305,7 +334,7 @@ Things to note: - There is no way to transform a non-standby cluster to a standby cluster through the operator. Adding the standby section to the manifest of a running Postgres cluster will have no effect. However, it can be done through Patroni - by adding the [standby_cluster] (https://github.com/zalando/patroni/blob/bd2c54581abb42a7d3a3da551edf0b8732eefd27/docs/replica_bootstrap.rst#standby-cluster) + by adding the [standby_cluster](https://github.com/zalando/patroni/blob/bd2c54581abb42a7d3a3da551edf0b8732eefd27/docs/replica_bootstrap.rst#standby-cluster) section using `patronictl edit-config`. Note that the transformed standby cluster will not be doing any streaming. It will be in standby mode and allow read-only transactions only. @@ -384,7 +413,7 @@ specified but globally disabled in the configuration. The ## Increase volume size -PostgreSQL operator supports statefulset volume resize if you're using the +Postgres operator supports statefulset volume resize if you're using the operator on top of AWS. For that you need to change the size field of the volume description in the cluster manifest and apply the change: diff --git a/manifests/standby-manifest.yaml b/manifests/standby-manifest.yaml index 49f2b1a1f..e1bcaf104 100644 --- a/manifests/standby-manifest.yaml +++ b/manifests/standby-manifest.yaml @@ -9,7 +9,7 @@ spec: size: 1Gi numberOfInstances: 1 postgresql: - version: "10" + version: "11" # Make this a standby cluster and provide the s3 bucket path of source cluster for continuous streaming. standby: s3_wal_path: "s3://path/to/bucket/containing/wal/of/source/cluster/" diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 1f8fe203f..0a7377389 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -227,6 +227,10 @@ func (c *Cluster) Create() error { c.setStatus(acidv1.ClusterStatusCreating) + if err = c.validateResources(&c.Spec); err != nil { + return fmt.Errorf("insufficient resource limits specified: %v", err) + } + for _, role := range []PostgresRole{Master, Replica} { if c.Endpoints[role] != nil { @@ -491,6 +495,44 @@ func compareResourcesAssumeFirstNotNil(a *v1.ResourceRequirements, b *v1.Resourc } +func (c *Cluster) validateResources(spec *acidv1.PostgresSpec) error { + + // setting limits too low can cause unnecessary evictions / OOM kills + const ( + cpuMinLimit = "256m" + memoryMinLimit = "256Mi" + ) + + var ( + isSmaller bool + err error + ) + + cpuLimit := spec.Resources.ResourceLimits.CPU + if cpuLimit != "" { + isSmaller, err = util.IsSmallerQuantity(cpuLimit, cpuMinLimit) + if err != nil { + return fmt.Errorf("error validating CPU limit: %v", err) + } + if isSmaller { + return fmt.Errorf("defined CPU limit %s is below required minimum %s to properly run postgresql resource", cpuLimit, cpuMinLimit) + } + } + + memoryLimit := spec.Resources.ResourceLimits.Memory + if memoryLimit != "" { + isSmaller, err = util.IsSmallerQuantity(memoryLimit, memoryMinLimit) + if err != nil { + return fmt.Errorf("error validating memory limit: %v", err) + } + if isSmaller { + return fmt.Errorf("defined memory limit %s is below required minimum %s to properly run postgresql resource", memoryLimit, memoryMinLimit) + } + } + + return nil +} + // Update changes Kubernetes objects according to the new specification. Unlike the sync case, the missing object // (i.e. service) is treated as an error // logical backup cron jobs are an exception: a user-initiated Update can enable a logical backup job @@ -501,6 +543,7 @@ func (c *Cluster) Update(oldSpec, newSpec *acidv1.Postgresql) error { c.mu.Lock() defer c.mu.Unlock() + oldStatus := c.Status c.setStatus(acidv1.ClusterStatusUpdating) c.setSpec(newSpec) @@ -512,6 +555,22 @@ func (c *Cluster) Update(oldSpec, newSpec *acidv1.Postgresql) error { } }() + if err := c.validateResources(&newSpec.Spec); err != nil { + err = fmt.Errorf("insufficient resource limits specified: %v", err) + + // cancel update only when (already too low) pod resources were edited + // if cluster was successfully running before the update, continue but log a warning + isCPULimitSmaller, err2 := util.IsSmallerQuantity(newSpec.Spec.Resources.ResourceLimits.CPU, oldSpec.Spec.Resources.ResourceLimits.CPU) + isMemoryLimitSmaller, err3 := util.IsSmallerQuantity(newSpec.Spec.Resources.ResourceLimits.Memory, oldSpec.Spec.Resources.ResourceLimits.Memory) + + if oldStatus.Running() && !isCPULimitSmaller && !isMemoryLimitSmaller && err2 == nil && err3 == nil { + c.logger.Warning(err) + } else { + updateFailed = true + return err + } + } + if oldSpec.Spec.PgVersion != newSpec.Spec.PgVersion { // PG versions comparison c.logger.Warningf("postgresql version change(%q -> %q) has no effect", oldSpec.Spec.PgVersion, newSpec.Spec.PgVersion) //we need that hack to generate statefulset with the old version diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 73be712ca..c69c7a076 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -741,7 +741,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef limit = c.OpConfig.DefaultMemoryLimit } - isSmaller, err := util.RequestIsSmallerThanLimit(request, limit) + isSmaller, err := util.IsSmallerQuantity(request, limit) if err != nil { return nil, err } @@ -768,7 +768,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef limit = c.OpConfig.DefaultMemoryLimit } - isSmaller, err := util.RequestIsSmallerThanLimit(sidecarRequest, sidecarLimit) + isSmaller, err := util.IsSmallerQuantity(sidecarRequest, sidecarLimit) if err != nil { return nil, err } diff --git a/pkg/cluster/sync.go b/pkg/cluster/sync.go index dd55cd04c..abe579fb5 100644 --- a/pkg/cluster/sync.go +++ b/pkg/cluster/sync.go @@ -23,6 +23,7 @@ func (c *Cluster) Sync(newSpec *acidv1.Postgresql) error { c.mu.Lock() defer c.mu.Unlock() + oldStatus := c.Status c.setSpec(newSpec) defer func() { @@ -34,6 +35,16 @@ func (c *Cluster) Sync(newSpec *acidv1.Postgresql) error { } }() + if err = c.validateResources(&c.Spec); err != nil { + err = fmt.Errorf("insufficient resource limits specified: %v", err) + if oldStatus.Running() { + c.logger.Warning(err) + err = nil + } else { + return err + } + } + if err = c.initUsers(); err != nil { err = fmt.Errorf("could not init users: %v", err) return err diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 9db03ceb1..831078f3e 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -111,7 +111,7 @@ func (c *Controller) initOperatorConfig() { if c.opConfig.SetMemoryRequestToLimit { - isSmaller, err := util.RequestIsSmallerThanLimit(c.opConfig.DefaultMemoryRequest, c.opConfig.DefaultMemoryLimit) + isSmaller, err := util.IsSmallerQuantity(c.opConfig.DefaultMemoryRequest, c.opConfig.DefaultMemoryLimit) if err != nil { panic(err) } @@ -120,7 +120,7 @@ func (c *Controller) initOperatorConfig() { c.opConfig.DefaultMemoryRequest = c.opConfig.DefaultMemoryLimit } - isSmaller, err = util.RequestIsSmallerThanLimit(c.opConfig.ScalyrMemoryRequest, c.opConfig.ScalyrMemoryLimit) + isSmaller, err = util.IsSmallerQuantity(c.opConfig.ScalyrMemoryRequest, c.opConfig.ScalyrMemoryLimit) if err != nil { panic(err) } diff --git a/pkg/util/util.go b/pkg/util/util.go index a8ef460db..ad6de14a2 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -141,17 +141,17 @@ func Coalesce(val, defaultVal string) string { return val } -// RequestIsSmallerThanLimit : ... -func RequestIsSmallerThanLimit(requestStr, limitStr string) (bool, error) { +// IsSmallerQuantity : checks if first resource is of a smaller quantity than the second +func IsSmallerQuantity(requestStr, limitStr string) (bool, error) { request, err := resource.ParseQuantity(requestStr) if err != nil { - return false, fmt.Errorf("could not parse memory request %v : %v", requestStr, err) + return false, fmt.Errorf("could not parse request %v : %v", requestStr, err) } limit, err2 := resource.ParseQuantity(limitStr) if err2 != nil { - return false, fmt.Errorf("could not parse memory limit %v : %v", limitStr, err2) + return false, fmt.Errorf("could not parse limit %v : %v", limitStr, err2) } return request.Cmp(limit) == -1, nil diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index a34e57e23..1f86ea1b4 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -69,7 +69,7 @@ var substringMatch = []struct { {regexp.MustCompile(`aaaa (\d+) bbbb`), "aaaa 123 bbbb", nil}, } -var requestIsSmallerThanLimitTests = []struct { +var requestIsSmallerQuantityTests = []struct { request string limit string out bool @@ -155,14 +155,14 @@ func TestMapContains(t *testing.T) { } } -func TestRequestIsSmallerThanLimit(t *testing.T) { - for _, tt := range requestIsSmallerThanLimitTests { - res, err := RequestIsSmallerThanLimit(tt.request, tt.limit) +func TestIsSmallerQuantity(t *testing.T) { + for _, tt := range requestIsSmallerQuantityTests { + res, err := IsSmallerQuantity(tt.request, tt.limit) if err != nil { - t.Errorf("RequestIsSmallerThanLimit returned unexpected error: %#v", err) + t.Errorf("IsSmallerQuantity returned unexpected error: %#v", err) } if res != tt.out { - t.Errorf("RequestIsSmallerThanLimit expected: %#v, got: %#v", tt.out, res) + t.Errorf("IsSmallerQuantity expected: %#v, got: %#v", tt.out, res) } } } From bfe2e709a1f66ba44da8a9abab329e1c356241f8 Mon Sep 17 00:00:00 2001 From: zimbatm Date: Thu, 12 Dec 2019 16:27:40 +0000 Subject: [PATCH 17/21] go.mod: fix dependencies (#754) Fix build issue: go/pkg/mod/k8s.io/client-go@v11.0.0+incompatible/rest/request.go:598:31: not enough arguments in call to watch.NewStreamWatcher --- Makefile | 3 ++- go.mod | 18 +++++++++------- go.sum | 64 +++++++++++++++++++------------------------------------- 3 files changed, 33 insertions(+), 52 deletions(-) diff --git a/Makefile b/Makefile index f42cfe09a..dc1c790fe 100644 --- a/Makefile +++ b/Makefile @@ -79,7 +79,8 @@ scm-source.json: .git tools: GO111MODULE=on go get -u honnef.co/go/tools/cmd/staticcheck - GO111MODULE=on go get k8s.io/client-go@kubernetes-1.16.0 + GO111MODULE=on go get k8s.io/client-go@kubernetes-1.16.3 + GO111MODULE=on go mod tidy fmt: @gofmt -l -w -s $(DIRS) diff --git a/go.mod b/go.mod index b8c7b1615..36686dcf6 100644 --- a/go.mod +++ b/go.mod @@ -4,20 +4,22 @@ go 1.12 require ( github.com/aws/aws-sdk-go v1.25.44 + github.com/emicklei/go-restful v2.9.6+incompatible // indirect + github.com/evanphx/json-patch v4.5.0+incompatible // indirect + github.com/googleapis/gnostic v0.3.0 // indirect github.com/imdario/mergo v0.3.8 // indirect github.com/lib/pq v1.2.0 github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d github.com/sirupsen/logrus v1.4.2 - golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e // indirect - golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 // indirect - golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect - golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d // indirect + golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 // indirect + golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect + golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 // indirect + golang.org/x/tools v0.0.0-20191209225234-22774f7dae43 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.2.4 k8s.io/api v0.0.0-20191121015604-11707872ac1c - k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8 - k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a - k8s.io/client-go v11.0.0+incompatible + k8s.io/apiextensions-apiserver v0.0.0-20191204090421-cd61debedab5 + k8s.io/apimachinery v0.0.0-20191203211716-adc6f4cd9e7d + k8s.io/client-go v0.0.0-20191204082520-bc9b51d240b2 k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e - sigs.k8s.io/kind v0.5.1 // indirect ) diff --git a/go.sum b/go.sum index c7f7be037..f85dd060f 100644 --- a/go.sum +++ b/go.sum @@ -61,11 +61,9 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w= github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -138,7 +136,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -156,8 +153,6 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= @@ -174,7 +169,6 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -184,7 +178,6 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -209,7 +202,6 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= @@ -235,11 +227,9 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -264,21 +254,18 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -315,8 +302,8 @@ golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e h1:egKlR8l7Nu9vHGWbcUV8lqR4987UfUbBd7GbhqGzNYU= -golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495 h1:I6A9Ag9FpEKOjcKrRNjQkPHawoXIhKyTGfvvjFAiiAk= @@ -344,8 +331,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 h1:e6HwijUxhDe+hPNjZQQn9bA5PW3vNmnN64U2ZW759Lk= -golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= @@ -369,17 +356,15 @@ golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190621203818-d432491b9138/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= -golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -398,8 +383,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d h1:/iIZNFGxc/a7C3yWjGcnboV+Tkc7mxr+p6fDztwoxuM= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191209225234-22774f7dae43 h1:NfPq5mgc5ArFgVLCpeS4z07IoxSAqVfV/gQ5vxdgaxI= +golang.org/x/tools v0.0.0-20191209225234-22774f7dae43/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485 h1:OB/uP/Puiu5vS5QMRPrXCDWUPb+kt8f1KW8oQzFejQw= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= @@ -434,7 +419,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -442,33 +426,31 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20190313235455-40a48860b5ab/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.0.0-20191121015604-11707872ac1c h1:Z87my3sF4WhG0OMxzARkWY/IKBtOr+MhXZAb4ts6qFc= k8s.io/api v0.0.0-20191121015604-11707872ac1c/go.mod h1:R/s4gKT0V/cWEnbQa9taNRJNbWUK57/Dx6cPj6MD3A0= -k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8 h1:SrFLwOURsuwzuCi0zJdaBbPF31AcV9JUwpwIVosnnE4= -k8s.io/apiextensions-apiserver v0.0.0-20191121021419-88daf26ec3b8/go.mod h1:NMIy5Wa/or8CsLhYRleOp9CWAHVdcWpzT6Ufx1SNVjA= -k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a h1:9V03T5lHv/iF4fSgvMCd+iB86AgEgmzLpheMqIJy7hs= +k8s.io/apiextensions-apiserver v0.0.0-20191204090421-cd61debedab5 h1:g+GvnbGqLU1Jxb/9iFm/BFcmkqG9HdsGh52+wHirpsM= +k8s.io/apiextensions-apiserver v0.0.0-20191204090421-cd61debedab5/go.mod h1:CPw0IHz1YrWGy0+8mG/76oTHXvChlgCb3EAezKQKB2I= k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apiserver v0.0.0-20191121020624-6eed2f5a3289/go.mod h1:7P+0qMKoaggchirHLUSCVD22ohdkjN19+qQOKcAdfbI= -k8s.io/client-go v0.0.0-20191121015835-571c0ef67034 h1:+/ppGIi1rJThJAz/xJSSOuD82gb6E5jRv2305MSznxQ= -k8s.io/client-go v0.0.0-20191121015835-571c0ef67034/go.mod h1:Adhj+OyDRsEXTnL9BfL7xbLWGWMCqGLWpMqGHkZI4J8= -k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o= -k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/apimachinery v0.0.0-20191123233150-4c4803ed55e3/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.0.0-20191128180518-03184f823e28/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.0.0-20191203211716-adc6f4cd9e7d h1:q+OZmYewHJeMCzwpHkXlNTtk5bvaUMPCikKvf77RBlo= +k8s.io/apimachinery v0.0.0-20191203211716-adc6f4cd9e7d/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apiserver v0.0.0-20191204084332-137a9d3b886b/go.mod h1:itgfam5HJbT/4b2BGfpUkkxfheMmDH+Ix+tEAP3uqZk= +k8s.io/client-go v0.0.0-20191204082517-8c19b9f4a642/go.mod h1:HMVIZ0dPop3WCrPEaJ+v5/94cjt56avdDFshpX0Fjvo= +k8s.io/client-go v0.0.0-20191204082519-e9644b2e3edc/go.mod h1:5lSG1yeDZVwDYAHe9VK48SCe5zmcnkAcf2Mx59TuhmM= +k8s.io/client-go v0.0.0-20191204082520-bc9b51d240b2 h1:T2HGghBOPAOEjWuIyFSeCsWEwsxa6unkBvy3PHfqonM= +k8s.io/client-go v0.0.0-20191204082520-bc9b51d240b2/go.mod h1:5lSG1yeDZVwDYAHe9VK48SCe5zmcnkAcf2Mx59TuhmM= k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e h1:HB9Zu5ZUvJfNpLiTPhz+CebVKV8C39qTBMQkAgAZLNw= k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= -k8s.io/component-base v0.0.0-20191121020327-771114ba3383/go.mod h1:tv9ITs6VEFWkF+kHwY4GiFvDr9vUGKJ4X/8+Z+oqVLk= +k8s.io/component-base v0.0.0-20191204083903-0d4d24e738e4/go.mod h1:8VIh1jErItC4bg9hLBkPneyS77Tin8KwSzbYepHJnQI= +k8s.io/component-base v0.0.0-20191204083906-3ac1376c73aa/go.mod h1:mECWvHCPhJudDVDMtBl+AIf/YnTMp5r1F947OYFUwP0= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKOxmGeKRbsXVmqYM= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= @@ -478,10 +460,6 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -sigs.k8s.io/kind v0.5.1 h1:BYnHEJ9DC+0Yjlyyehqd3xnKtEmFdLKU8QxqOqvQzdw= -sigs.k8s.io/kind v0.5.1/go.mod h1:L+Kcoo83/D1+ryU5P2VFbvYm0oqbkJn9zTZq0KNxW68= -sigs.k8s.io/kustomize/v3 v3.1.1-0.20190821175718-4b67a6de1296 h1:iQaIG5Dq+3qSiaFrJ/l/0MjjxKmdwyVNpKRYJwUe/+0= -sigs.k8s.io/kustomize/v3 v3.1.1-0.20190821175718-4b67a6de1296/go.mod h1:ztX4zYc/QIww3gSripwF7TBOarBTm5BvyAMem0kCzOE= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= From 97e0d6d3888dc901aa3a089293ceb74972a7f5ae Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Thu, 12 Dec 2019 17:55:41 +0100 Subject: [PATCH 18/21] extend docs and polish manifest examples (#762) --- docs/administrator.md | 59 +++++++----- docs/developer.md | 12 +-- docs/index.md | 2 +- docs/quickstart.md | 3 + docs/reference/cluster_manifest.md | 14 +-- docs/reference/operator_parameters.md | 4 +- docs/user.md | 110 ++++++++++------------ manifests/complete-postgres-manifest.yaml | 2 +- manifests/minimal-postgres-manifest.yaml | 2 +- manifests/standby-manifest.yaml | 2 +- pkg/apis/acid.zalan.do/v1/util_test.go | 6 +- pkg/util/teams/teams_test.go | 4 +- 12 files changed, 111 insertions(+), 109 deletions(-) diff --git a/docs/administrator.md b/docs/administrator.md index 5cde06ade..5b8769edb 100644 --- a/docs/administrator.md +++ b/docs/administrator.md @@ -3,6 +3,26 @@ Learn how to configure and manage the Postgres Operator in your Kubernetes (K8s) environment. +## Minor and major version upgrade + +Minor version upgrades for PostgreSQL are handled via updating the Spilo Docker +image. The operator will carry out a rolling update of Pods which includes a +switchover (planned failover) of the master to the Pod with new minor version. +The switch should usually take less than 5 seconds, still clients have to +reconnect. + +Major version upgrades are supported via [cloning](user.md#clone-directly). The +new cluster manifest must have a higher `version` string than the source cluster +and will be created from a basebackup. Depending of the cluster size, downtime +in this case can be significant as writes to the database should be stopped and +all WAL files should be archived first before cloning is started. + +Note, that simply changing the version string in the `postgresql` manifest does +not work at present and leads to errors. Neither Patroni nor Postgres Operator +can do in place `pg_upgrade`. Still, it can be executed manually in the Postgres +container, which is tricky (i.e. systems need to be stopped, replicas have to be +synced) but of course faster than cloning. + ## CRD Validation [CustomResourceDefinitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) @@ -95,8 +115,6 @@ is used by the operator to connect to the clusters after creation. ## Role-based access control for the operator -### Service account and cluster roles - The manifest [`operator-service-account-rbac.yaml`](../manifests/operator-service-account-rbac.yaml) defines the service account, cluster roles and bindings needed for the operator to function under access control restrictions. To deploy the operator with this @@ -109,6 +127,8 @@ kubectl create -f manifests/postgres-operator.yaml kubectl create -f manifests/minimal-postgres-manifest.yaml ``` +### Service account and cluster roles + Note that the service account is named `zalando-postgres-operator`. You may have to change the `service_account_name` in the operator ConfigMap and `serviceAccountName` in the `postgres-operator` deployment appropriately. This @@ -116,12 +136,6 @@ is done intentionally to avoid breaking those setups that already work with the default `operator` account. In the future the operator should ideally be run under the `zalando-postgres-operator` service account. -The service account defined in `operator-service-account-rbac.yaml` acquires -some privileges not used by the operator (i.e. we only need `list` and `watch` -on `configmaps` resources). This is also done intentionally to avoid breaking -things if someone decides to configure the same service account in the -operator's ConfigMap to run Postgres clusters. - ### Give K8s users access to create/list `postgresqls` By default `postgresql` custom resources can only be listed and changed by @@ -157,7 +171,6 @@ metadata: name: postgres-operator data: toleration: "key:postgres,operator:Exists,effect:NoSchedule" - ... ``` For an OperatorConfiguration resource the toleration should be defined like @@ -172,7 +185,6 @@ configuration: kubernetes: toleration: postgres: "key:postgres,operator:Exists,effect:NoSchedule" - ... ``` Note that the K8s version 1.13 brings [taint-based eviction](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/#taint-based-evictions) @@ -250,7 +262,6 @@ metadata: name: postgres-operator data: inherited_labels: application,environment - ... ``` **OperatorConfiguration** @@ -265,7 +276,6 @@ configuration: inherited_labels: - application - environment -... ``` **cluster manifest** @@ -279,7 +289,7 @@ metadata: application: my-app environment: demo spec: -... + ... ``` **network policy** @@ -294,7 +304,6 @@ spec: matchLabels: application: my-app environment: demo -... ``` @@ -317,7 +326,6 @@ metadata: data: # referencing config map with custom settings pod_environment_configmap: postgres-pod-config - ... ``` **OperatorConfiguration** @@ -331,7 +339,6 @@ configuration: kubernetes: # referencing config map with custom settings pod_environment_configmap: postgres-pod-config - ... ``` **referenced ConfigMap `postgres-pod-config`** @@ -412,12 +419,12 @@ external systems but defined for an individual Postgres cluster in its manifest. A typical example is a role for connections from an application that uses the database. -* **Human users** originate from the Teams API that returns a list of the team -members given a team id. The operator differentiates between (a) product teams -that own a particular Postgres cluster and are granted admin rights to maintain -it, and (b) Postgres superuser teams that get the superuser access to all -Postgres databases running in a K8s cluster for the purposes of maintaining and -troubleshooting. +* **Human users** originate from the [Teams API](user.md#teams-api-roles) that +returns a list of the team members given a team id. The operator differentiates +between (a) product teams that own a particular Postgres cluster and are granted +admin rights to maintain it, and (b) Postgres superuser teams that get the +superuser access to all Postgres databases running in a K8s cluster for the +purposes of maintaining and troubleshooting. ## Understanding rolling update of Spilo pods @@ -481,7 +488,7 @@ A secret can be pre-provisioned in different ways: With the v1.2 release the Postgres Operator is shipped with a browser-based configuration user interface (UI) that simplifies managing Postgres clusters -with the operator. The UI runs with Node.js and comes with it's own docker +with the operator. The UI runs with Node.js and comes with it's own Docker image. Run NPM to continuously compile `tags/js` code. Basically, it creates an @@ -493,14 +500,14 @@ Run NPM to continuously compile `tags/js` code. Basically, it creates an To build the Docker image open a shell and change to the `ui` folder. Then run: -``` +```bash docker build -t registry.opensource.zalan.do/acid/postgres-operator-ui:v1.2.0 . ``` Apply all manifests for the `ui/manifests` folder to deploy the Postgres Operator UI on K8s. For local tests you don't need the Ingress resource. -``` +```bash kubectl apply -f ui/manifests ``` @@ -510,6 +517,6 @@ to the K8s and Postgres Operator REST API. You can use the provided `run_local.sh` script for this. Make sure it uses the correct URL to your K8s API server, e.g. for minikube it would be `https://192.168.99.100:8443`. -``` +```bash ./run_local.sh ``` diff --git a/docs/developer.md b/docs/developer.md index f8351e28a..6e0fc33c8 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -40,7 +40,7 @@ This would take a while to complete. You have to redo `make deps` every time your dependencies list changes, i.e. after adding a new library dependency. 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 +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 `registry.opensource.zalan.do/acid/postgres-operator` @@ -60,10 +60,10 @@ The binary will be placed into the build directory. ## Deploying self build image -The fastest way to run and test your docker image locally is to reuse the docker -from [minikube](https://github.com/kubernetes/minikube/releases) or use the -`load docker-image` from [kind](https://kind.sigs.k8s.io/). The following steps -will get you the docker image built and deployed. +The fastest way to run and test your Docker image locally is to reuse the Docker +environment from [minikube](https://github.com/kubernetes/minikube/releases) +or use the `load docker-image` from [kind](https://kind.sigs.k8s.io/). The +following steps will get you the Docker image built and deployed. ```bash # minikube @@ -162,7 +162,7 @@ The operator also supports pprof endpoints listed at the * /debug/pprof/trace It's possible to attach a debugger to troubleshoot postgres-operator inside a -docker container. It's possible with [gdb](https://www.gnu.org/software/gdb/) +Docker container. It's possible with [gdb](https://www.gnu.org/software/gdb/) and [delve](https://github.com/derekparker/delve). Since the latter one is a specialized debugger for Go, we will use it as an example. To use it you need: diff --git a/docs/index.md b/docs/index.md index c0e78ac32..87b08deb2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,7 +13,7 @@ manages PostgreSQL clusters on Kubernetes (K8s): 2. The operator also watches updates to [its own configuration](../manifests/configmap.yaml) and alters running Postgres clusters if necessary. For instance, if the - docker image in a pod is changed, the operator carries out the rolling + Docker image in a pod is changed, the operator carries out the rolling update, which means it re-spawns pods of each managed StatefulSet one-by-one with the new Docker image. diff --git a/docs/quickstart.md b/docs/quickstart.md index 2da2cab7c..8cc5bc0c0 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -155,9 +155,12 @@ export PGPORT=$(echo $HOST_PORT | cut -d: -f 2) ``` Retrieve the password from the K8s Secret that is created in your cluster. +Non-encrypted connections are rejected by default, so set the SSL mode to +require: ```bash export PGPASSWORD=$(kubectl get secret postgres.acid-minimal-cluster.credentials -o 'jsonpath={.data.password}' | base64 -d) +export PGSSLMODE=require psql -U postgres ``` diff --git a/docs/reference/cluster_manifest.md b/docs/reference/cluster_manifest.md index cf522d73d..bf6df681b 100644 --- a/docs/reference/cluster_manifest.md +++ b/docs/reference/cluster_manifest.md @@ -62,7 +62,7 @@ These parameters are grouped directly under the `spec` key in the manifest. field. * **dockerImage** - custom docker image that overrides the **docker_image** operator parameter. + custom Docker image that overrides the **docker_image** operator parameter. It should be a [Spilo](https://github.com/zalando/spilo) image. Optional. * **spiloFSGroup** @@ -124,7 +124,7 @@ These parameters are grouped directly under the `spec` key in the manifest. * **enableShmVolume** - Start a database pod without limitations on shm memory. By default docker + Start a database pod without limitations on shm memory. By default Docker limit `/dev/shm` to `64M` (see e.g. the [docker issue](https://github.com/docker-library/postgres/issues/416), which could be not enough if PostgreSQL uses parallel workers heavily. If this option is @@ -185,19 +185,19 @@ explanation of `ttl` and `loop_wait` parameters. * **ttl** Patroni `ttl` parameter value, optional. The default is set by the Spilo - docker image. Optional. + Docker image. Optional. * **loop_wait** Patroni `loop_wait` parameter value, optional. The default is set by the - Spilo docker image. Optional. + Spilo Docker image. Optional. * **retry_timeout** Patroni `retry_timeout` parameter value, optional. The default is set by the - Spilo docker image. Optional. + Spilo Docker image. Optional. * **maximum_lag_on_failover** Patroni `maximum_lag_on_failover` parameter value, optional. The default is - set by the Spilo docker image. Optional. + set by the Spilo Docker image. Optional. * **slots** permanent replication slots that Patroni preserves after failover by @@ -320,7 +320,7 @@ defined in the sidecar dictionary: name of the sidecar. Required. * **image** - docker image of the sidecar. Required. + Docker image of the sidecar. Required. * **env** a dictionary of environment variables. Use usual Kubernetes definition diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index 3de4a5be4..1055d89b6 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -81,13 +81,13 @@ Those are top-level keys, containing both leaf keys and groups. Kubernetes-native DCS). * **docker_image** - Spilo docker image for Postgres instances. For production, don't rely on the + Spilo Docker image for Postgres instances. For production, don't rely on the default image, as it might be not the most up-to-date one. Instead, build your own Spilo image from the [github repository](https://github.com/zalando/spilo). * **sidecar_docker_images** - a map of sidecar names to docker images to run with Spilo. In case of the name + a map of sidecar names to Docker images to run with Spilo. In case of the name conflict with the definition in the cluster manifest the cluster-specific one is preferred. diff --git a/docs/user.md b/docs/user.md index d9e92d5d6..45f345c87 100644 --- a/docs/user.md +++ b/docs/user.md @@ -13,7 +13,7 @@ kind: postgresql metadata: name: acid-minimal-cluster spec: - teamId: "ACID" + teamId: "acid" volume: size: 1Gi numberOfInstances: 2 @@ -40,8 +40,16 @@ you can find this example also in the manifests folder: kubectl create -f manifests/minimal-postgres-manifest.yaml ``` -Note, that the minimum volume size to run the `postgresql` resource on Elastic -Block Storage (EBS) is `1Gi`. +Make sure, the `spec` section of the manifest contains at least a `teamId`, the +`numberOfInstances` and the `postgresql` object with the `version` specified. +The minimum volume size to run the `postgresql` resource on Elastic Block +Storage (EBS) is `1Gi`. + +Note, that the name of the cluster must start with the `teamId` and `-`. At +Zalando we use team IDs (nicknames) to lower the chance of duplicate cluster +names and colliding entities. The team ID would also be used to query an API to +get all members of a team and create [database roles](#teams-api-roles) for +them. ## Watch pods being created @@ -65,10 +73,12 @@ kubectl port-forward $PGMASTER 6432:5432 Open another CLI and connect to the database. Use the generated secret of the `postgres` robot user to connect to our `acid-minimal-cluster` master running -in Minikube: +in Minikube. As non-encrypted connections are rejected by default set the SSL +mode to require: ```bash export PGPASSWORD=$(kubectl get secret postgres.acid-minimal-cluster.credentials -o 'jsonpath={.data.password}' | base64 -d) +export PGSSLMODE=require psql -U postgres -p 6432 ``` @@ -80,8 +90,7 @@ cluster. It covers three use-cases: * `manifest roles`: create application roles specific to the cluster described in the manifest. * `infrastructure roles`: create application roles that should be automatically -created on every - cluster managed by the operator. +created on every cluster managed by the operator. * `teams API roles`: automatically create users for every member of the team owning the database cluster. @@ -131,9 +140,9 @@ The infrastructure roles secret is specified by the `infrastructure_roles_secret parameter. The role definition looks like this (values are base64 encoded): ```yaml - user1: ZGJ1c2Vy - password1: c2VjcmV0 - inrole1: b3BlcmF0b3I= +user1: ZGJ1c2Vy +password1: c2VjcmV0 +inrole1: b3BlcmF0b3I= ``` The block above describes the infrastructure role 'dbuser' with password @@ -154,19 +163,19 @@ secret and a ConfigMap. The ConfigMap must have the same name as the secret. The secret should contain an entry with 'rolename:rolepassword' for each role. ```yaml - dbuser: c2VjcmV0 +dbuser: c2VjcmV0 ``` And the role description for that user should be specified in the ConfigMap. ```yaml - data: - dbuser: | - inrole: [operator, admin] # following roles will be assigned to the new user - user_flags: - - createdb - db_parameters: # db parameters, applied for this particular user - log_statement: all +data: + dbuser: | + inrole: [operator, admin] # following roles will be assigned to the new user + user_flags: + - createdb + db_parameters: # db parameters, applied for this particular user + log_statement: all ``` One can allow membership in multiple roles via the `inrole` array parameter, @@ -185,16 +194,34 @@ See [infrastructure roles secret](../manifests/infrastructure-roles.yaml) and [infrastructure roles configmap](../manifests/infrastructure-roles-configmap.yaml) for the examples. +### Teams API roles + +These roles are meant for database activity of human users. It's possible to +configure the operator to automatically create database roles for lets say all +employees of one team. They are not listed in the manifest and there are no K8s +secrets created for them. Instead they would use an OAuth2 token to connect. To +get all members of the team the operator queries a defined API endpoint that +returns usernames. A minimal Teams API should work like this: + +``` +/.../ -> ["name","anothername"] +``` + +A ["fake" Teams API](../manifests/fake-teams-api.yaml) deployment is provided +in the manifests folder to set up a basic API around whatever services is used +for user management. The Teams API's URL is set in the operator's +[configuration](reference/operator_parameters.md#automatic-creation-of-human-users-in-the-database) +and `enable_teams_api` must be set to `true`. There are more settings available +to choose superusers, group roles, [PAM configuration](https://github.com/CyberDem0n/pam-oauth2) +etc. An OAuth2 token can be passed to the Teams API via a secret. The name for +this secret is configurable with the `oauth_token_secret_name` parameter. + ## Resource definition The compute resources to be used for the Postgres containers in the pods can be specified in the postgresql cluster manifest. ```yaml -apiVersion: "acid.zalan.do/v1" -kind: postgresql -metadata: - name: acid-minimal-cluster spec: resources: requests: @@ -218,12 +245,7 @@ you can use [taints and tolerations](https://kubernetes.io/docs/concepts/configu and configure the required toleration in the manifest. ```yaml -apiVersion: "acid.zalan.do/v1" -kind: postgresql -metadata: - name: acid-minimal-cluster spec: - teamId: "ACID" tolerations: - key: postgres operator: Exists @@ -241,11 +263,6 @@ section in the spec. There are two options here: ### Clone directly ```yaml -apiVersion: "acid.zalan.do/v1" -kind: postgresql - -metadata: - name: acid-test-cluster spec: clone: cluster: "acid-batman" @@ -261,11 +278,6 @@ means that you can clone only from clusters within the same namespace. ### Clone from S3 ```yaml -apiVersion: "acid.zalan.do/v1" -kind: postgresql - -metadata: - name: acid-test-cluster spec: clone: uid: "efd12e58-5786-11e8-b5a7-06148230260c" @@ -294,10 +306,6 @@ For non AWS S3 following settings can be set to support cloning from other S3 implementations: ```yaml -apiVersion: "acid.zalan.do/v1" -kind: postgresql -metadata: - name: acid-test-cluster spec: clone: uid: "efd12e58-5786-11e8-b5a7-06148230260c" @@ -346,13 +354,7 @@ used for log aggregation, monitoring, backups or other tasks. A sidecar can be specified like this: ```yaml -apiVersion: "acid.zalan.do/v1" -kind: postgresql - -metadata: - name: acid-minimal-cluster spec: - ... sidecars: - name: "container-name" image: "company/image:tag" @@ -390,13 +392,7 @@ be used to run custom actions before any normal and sidecar containers start. An init container can be specified like this: ```yaml -apiVersion: "acid.zalan.do/v1" -kind: postgresql - -metadata: - name: acid-minimal-cluster spec: - ... initContainers: - name: "container-name" image: "company/image:tag" @@ -417,12 +413,7 @@ Postgres operator supports statefulset volume resize if you're using the operator on top of AWS. For that you need to change the size field of the volume description in the cluster manifest and apply the change: -``` -apiVersion: "acid.zalan.do/v1" -kind: postgresql - -metadata: - name: acid-test-cluster +```yaml spec: volume: size: 5Gi # new volume size @@ -451,7 +442,8 @@ size of volumes that correspond to the previously running pods is not changed. You can enable logical backups from the cluster manifest by adding the following parameter in the spec section: -``` +```yaml +spec: enableLogicalBackup: true ``` diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index f8495caad..ba2315753 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -10,7 +10,7 @@ spec: - name: date image: busybox command: [ "/bin/date" ] - teamId: "ACID" + teamId: "acid" volume: size: 1Gi # storageClass: my-sc diff --git a/manifests/minimal-postgres-manifest.yaml b/manifests/minimal-postgres-manifest.yaml index 91d297cac..75dfdf07f 100644 --- a/manifests/minimal-postgres-manifest.yaml +++ b/manifests/minimal-postgres-manifest.yaml @@ -4,7 +4,7 @@ metadata: name: acid-minimal-cluster namespace: default spec: - teamId: "ACID" + teamId: "acid" volume: size: 1Gi numberOfInstances: 2 diff --git a/manifests/standby-manifest.yaml b/manifests/standby-manifest.yaml index e1bcaf104..e5299bc9b 100644 --- a/manifests/standby-manifest.yaml +++ b/manifests/standby-manifest.yaml @@ -4,7 +4,7 @@ metadata: name: acid-standby-cluster namespace: default spec: - teamId: "ACID" + teamId: "acid" volume: size: 1Gi numberOfInstances: 1 diff --git a/pkg/apis/acid.zalan.do/v1/util_test.go b/pkg/apis/acid.zalan.do/v1/util_test.go index cf3b080a5..fc068b322 100644 --- a/pkg/apis/acid.zalan.do/v1/util_test.go +++ b/pkg/apis/acid.zalan.do/v1/util_test.go @@ -180,7 +180,7 @@ var unmarshalCluster = []struct { "name": "acid-testcluster1" }, "spec": { - "teamId": "ACID", + "teamId": "acid", "pod_priority_class_name": "spilo-pod-priority", "volume": { "size": "5Gi", @@ -290,7 +290,7 @@ var unmarshalCluster = []struct { ResourceLimits: ResourceDescription{CPU: "300m", Memory: "3000Mi"}, }, - TeamID: "ACID", + TeamID: "acid", AllowedSourceRanges: []string{"127.0.0.1/32"}, NumberOfInstances: 2, Users: map[string]UserFlags{"zalando": {"superuser", "createdb"}}, @@ -319,7 +319,7 @@ var unmarshalCluster = []struct { }, Error: "", }, - marshal: []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"9.6","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"pod_priority_class_name":"spilo-pod-priority","volume":{"size":"5Gi","storageClass":"SSD", "subPath": "subdir"},"enableShmVolume":false,"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"ACID","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`), + marshal: []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"9.6","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"pod_priority_class_name":"spilo-pod-priority","volume":{"size":"5Gi","storageClass":"SSD", "subPath": "subdir"},"enableShmVolume":false,"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"acid","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`), err: nil}, // example with teamId set in input { diff --git a/pkg/util/teams/teams_test.go b/pkg/util/teams/teams_test.go index 637c4e16c..51bbcbc31 100644 --- a/pkg/util/teams/teams_test.go +++ b/pkg/util/teams/teams_test.go @@ -24,7 +24,7 @@ var teamsAPItc = []struct { {`{ "dn": "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", "id": "acid", -"id_name": "ACID", +"id_name": "acid", "team_id": "111222", "type": "official", "name": "Acid team name", @@ -70,7 +70,7 @@ var teamsAPItc = []struct { &Team{ Dn: "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", ID: "acid", - TeamName: "ACID", + TeamName: "acid", TeamID: "111222", Type: "official", FullName: "Acid team name", From 629feac98f275f01e6cdbfa2ed350cb6ef1f4a20 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Mon, 16 Dec 2019 17:07:36 +0100 Subject: [PATCH 19/21] Remove bind verb and explain privileges (#765) Closes #256 --- manifests/operator-service-account-rbac.yaml | 28 +++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/manifests/operator-service-account-rbac.yaml b/manifests/operator-service-account-rbac.yaml index e95fe320b..a37abe476 100644 --- a/manifests/operator-service-account-rbac.yaml +++ b/manifests/operator-service-account-rbac.yaml @@ -10,6 +10,7 @@ kind: ClusterRole metadata: name: zalando-postgres-operator rules: +# all verbs allowed for custom operator resources - apiGroups: - acid.zalan.do resources: @@ -18,6 +19,7 @@ rules: - operatorconfigurations verbs: - "*" +# to create or get/update CRDs when starting up - apiGroups: - apiextensions.k8s.io resources: @@ -27,12 +29,14 @@ rules: - get - patch - update +# to read configuration from ConfigMaps - apiGroups: - "" resources: - configmaps verbs: - get +# to manage endpoints which are also used by Patroni - apiGroups: - "" resources: @@ -45,6 +49,7 @@ rules: - list - patch - watch # needed if zalando-postgres-operator account is used for pods as well +# to CRUD secrets for database access - apiGroups: - "" resources: @@ -54,6 +59,7 @@ rules: - update - delete - get +# to check nodes for node readiness label - apiGroups: - "" resources: @@ -62,6 +68,7 @@ rules: - get - list - watch +# to read or delete existing PVCs. Creation via StatefulSet - apiGroups: - "" resources: @@ -70,6 +77,7 @@ rules: - delete - get - list + # to read existing PVs. Creation should be done via dynamic provisioning - apiGroups: - "" resources: @@ -78,6 +86,7 @@ rules: - get - list - update # only for resizing AWS volumes +# to watch Spilo pods and do rolling updates. Creation via StatefulSet - apiGroups: - "" resources: @@ -88,12 +97,14 @@ rules: - list - watch - patch +# to resize the filesystem in Spilo pods when increasing volume size - apiGroups: - "" resources: - pods/exec verbs: - create +# to CRUD services to point to Postgres cluster instances - apiGroups: - "" resources: @@ -103,6 +114,7 @@ rules: - delete - get - patch +# to CRUD the StatefulSet which controls the Postgres cluster instances - apiGroups: - apps resources: @@ -113,12 +125,14 @@ rules: - get - list - patch +# to get namespaces operator resources can run in - apiGroups: - "" resources: - namespaces verbs: - get +# to define PDBs. Update happens via delete/create - apiGroups: - policy resources: @@ -127,6 +141,7 @@ rules: - create - delete - get +# to create ServiceAccounts in each namespace the operator watches - apiGroups: - "" resources: @@ -134,6 +149,7 @@ rules: verbs: - get - create +# to create role bindings to the operator service account - apiGroups: - "rbac.authorization.k8s.io" resources: @@ -141,18 +157,11 @@ rules: verbs: - get - create -- apiGroups: - - "rbac.authorization.k8s.io" - resources: - - clusterroles - verbs: - - bind - resourceNames: - - zalando-postgres-operator +# to CRUD cron jobs for logical backups - apiGroups: - batch resources: - - cronjobs # enables logical backups + - cronjobs verbs: - create - delete @@ -160,6 +169,7 @@ rules: - list - patch - update + --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding From 182e3bc7db0fd6c7b2617286c324167c7f0c158e Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Mon, 16 Dec 2019 17:08:09 +0100 Subject: [PATCH 20/21] add missing fields to OperatorConfiguration CRD validation (#767) --- .../crds/operatorconfigurations.yaml | 30 +++++++----- manifests/complete-postgres-manifest.yaml | 35 ++++++++------ manifests/operatorconfiguration.crd.yaml | 30 +++++++----- ...gresql-operator-default-configuration.yaml | 12 +++-- manifests/standby-manifest.yaml | 4 -- pkg/apis/acid.zalan.do/v1/crds.go | 46 ++++++++++++------- .../v1/operator_configuration_type.go | 32 +++++-------- .../acid.zalan.do/v1/zz_generated.deepcopy.go | 28 ----------- pkg/util/config/config.go | 2 +- 9 files changed, 109 insertions(+), 110 deletions(-) diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index d50a2b431..c97e246ab 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -121,6 +121,8 @@ spec: type: array items: type: string + master_pod_move_timeout: + type: string node_readiness_label: type: object additionalProperties: @@ -138,10 +140,16 @@ spec: enum: - "ordered_ready" - "parallel" + pod_priority_class_name: + type: string pod_role_label: type: string + pod_service_account_definition: + type: string pod_service_account_name: type: string + pod_service_account_role_binding_definition: + type: string pod_terminate_grace_period: type: string secret_name_template: @@ -189,16 +197,16 @@ spec: load_balancer: type: object properties: + custom_service_annotations: + type: object + additionalProperties: + type: string db_hosted_zone: type: string enable_master_load_balancer: type: boolean enable_replica_load_balancer: type: boolean - custom_service_annotations: - type: object - additionalProperties: - type: string master_dns_name_format: type: string replica_dns_name_format: @@ -221,21 +229,21 @@ spec: logical_backup: type: object properties: - logical_backup_schedule: - type: string - pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' logical_backup_docker_image: type: string + logical_backup_s3_access_key_id: + type: string logical_backup_s3_bucket: type: string logical_backup_s3_endpoint: type: string - logical_backup_s3_sse: - type: string - logical_backup_s3_access_key_id: - type: string logical_backup_s3_secret_access_key: type: string + logical_backup_s3_sse: + type: string + logical_backup_schedule: + type: string + pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' debug: type: object properties: diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index ba2315753..23dd40638 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -6,10 +6,6 @@ metadata: # environment: demo spec: dockerImage: registry.opensource.zalan.do/acid/spilo-11:1.6-p1 - initContainers: - - name: date - image: busybox - command: [ "/bin/date" ] teamId: "acid" volume: size: 1Gi @@ -25,18 +21,22 @@ spec: - 127.0.0.1/32 databases: foo: zalando -# podAnnotations: -# annotation.key: value -# Expert section - - enableShmVolume: true -# spiloFSGroup: 103 postgresql: version: "11" - parameters: + parameters: # Expert section shared_buffers: "32MB" max_connections: "10" log_statement: "all" + + enableShmVolume: true +# spiloFSGroup: 103 +# podAnnotations: +# annotation.key: value +# podPriorityClassName: "spilo-pod-priority" +# tolerations: +# - key: postgres +# operator: Exists +# effect: NoSchedule resources: requests: cpu: 10m @@ -63,6 +63,7 @@ spec: loop_wait: &loop_wait 10 retry_timeout: 10 maximum_lag_on_failover: 33554432 + # restore a Postgres DB with point-in-time-recovery # with a non-empty timestamp, clone from an S3 bucket using the latest backup before the timestamp # with an empty/absent timestamp, clone from an existing alive cluster using pg_basebackup @@ -75,9 +76,15 @@ spec: # run periodic backups with k8s cron jobs # enableLogicalBackup: true # logicalBackupSchedule: "30 00 * * *" - maintenanceWindows: - - 01:00-06:00 #UTC - - Sat:00:00-04:00 + +# maintenanceWindows: +# - 01:00-06:00 #UTC +# - Sat:00:00-04:00 + + initContainers: + - name: date + image: busybox + command: [ "/bin/date" ] # sidecars: # - name: "telegraf-sidecar" # image: "telegraf:latest" diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index bed892dc8..810624bc4 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -97,6 +97,8 @@ spec: type: array items: type: string + master_pod_move_timeout: + type: string node_readiness_label: type: object additionalProperties: @@ -114,10 +116,16 @@ spec: enum: - "ordered_ready" - "parallel" + pod_priority_class_name: + type: string pod_role_label: type: string + pod_service_account_definition: + type: string pod_service_account_name: type: string + pod_service_account_role_binding_definition: + type: string pod_terminate_grace_period: type: string secret_name_template: @@ -165,16 +173,16 @@ spec: load_balancer: type: object properties: + custom_service_annotations: + type: object + additionalProperties: + type: string db_hosted_zone: type: string enable_master_load_balancer: type: boolean enable_replica_load_balancer: type: boolean - custom_service_annotations: - type: object - additionalProperties: - type: string master_dns_name_format: type: string replica_dns_name_format: @@ -197,21 +205,21 @@ spec: logical_backup: type: object properties: - logical_backup_schedule: - type: string - pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' logical_backup_docker_image: type: string + logical_backup_s3_access_key_id: + type: string logical_backup_s3_bucket: type: string logical_backup_s3_endpoint: type: string - logical_backup_s3_sse: - type: string - logical_backup_s3_access_key_id: - type: string logical_backup_s3_secret_access_key: type: string + logical_backup_s3_sse: + type: string + logical_backup_schedule: + type: string + pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' debug: type: object properties: diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index 84e12b4ee..cdfe0f573 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -21,7 +21,7 @@ configuration: kubernetes: cluster_domain: cluster.local cluster_labels: - application: spilo + application: spilo cluster_name_label: cluster-name # custom_pod_annotations: # keya: valuea @@ -34,6 +34,7 @@ configuration: # inherited_labels: # - application # - environment + master_pod_move_timeout: 20m # node_readiness_label: # status: ready oauth_token_secret_name: postgresql-operator @@ -41,8 +42,11 @@ configuration: pod_antiaffinity_topology_key: "kubernetes.io/hostname" # pod_environment_configmap: "" pod_management_policy: "ordered_ready" + # pod_priority_class_name: "" pod_role_label: spilo-role + # pod_service_account_definition: "" pod_service_account_name: zalando-postgres-operator + # pod_service_account_role_binding_definition: "" pod_terminate_grace_period: 5m secret_name_template: "{username}.{cluster}.credentials.{tprkind}.{tprgroup}" # spilo_fsgroup: 103 @@ -79,10 +83,10 @@ configuration: # wal_s3_bucket: "" logical_backup: logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" - logical_backup_s3_access_key_id: "" + # logical_backup_s3_access_key_id: "" logical_backup_s3_bucket: "my-bucket-url" - logical_backup_s3_endpoint: "" - logical_backup_s3_secret_access_key: "" + # logical_backup_s3_endpoint: "" + # logical_backup_s3_secret_access_key: "" logical_backup_s3_sse: "AES256" logical_backup_schedule: "30 00 * * *" debug: diff --git a/manifests/standby-manifest.yaml b/manifests/standby-manifest.yaml index e5299bc9b..2b621bd10 100644 --- a/manifests/standby-manifest.yaml +++ b/manifests/standby-manifest.yaml @@ -13,7 +13,3 @@ spec: # Make this a standby cluster and provide the s3 bucket path of source cluster for continuous streaming. standby: s3_wal_path: "s3://path/to/bucket/containing/wal/of/source/cluster/" - - maintenanceWindows: - - 01:00-06:00 #UTC - - Sat:00:00-04:00 diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index 75704afde..20fa37138 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -717,6 +717,9 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation }, }, }, + "master_pod_move_timeout": { + Type: "string", + }, "node_readiness_label": { Type: "object", AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ @@ -748,12 +751,21 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation }, }, }, + "pod_priority_class_name": { + Type: "string", + }, "pod_role_label": { Type: "string", }, + "pod_service_account_definition": { + Type: "string", + }, "pod_service_account_name": { Type: "string", }, + "pod_service_account_role_binding_definition": { + Type: "string", + }, "pod_terminate_grace_period": { Type: "string", }, @@ -826,6 +838,14 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation "load_balancer": { Type: "object", Properties: map[string]apiextv1beta1.JSONSchemaProps{ + "custom_service_annotations": { + Type: "object", + AdditionalProperties: &apiextv1beta1.JSONSchemaPropsOrBool{ + Schema: &apiextv1beta1.JSONSchemaProps{ + Type: "string", + }, + }, + }, "db_hosted_zone": { Type: "string", }, @@ -835,14 +855,6 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation "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", }, @@ -877,27 +889,27 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation "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_access_key_id": { + Type: "string", + }, "logical_backup_s3_bucket": { Type: "string", }, "logical_backup_s3_endpoint": { Type: "string", }, + "logical_backup_s3_secret_access_key": { + Type: "string", + }, "logical_backup_s3_sse": { Type: "string", }, - "logical_backup_s3_access_key_id": { - Type: "string", - }, - "logical_backup_s3_secret_access_key": { - Type: "string", + "logical_backup_schedule": { + Type: "string", + Pattern: "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$", }, }, }, 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 f76790ad5..948c7cbbf 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -118,7 +118,7 @@ type OperatorDebugConfiguration struct { EnableDBAccess bool `json:"enable_database_access,omitempty"` } -// TeamsAPIConfiguration defines the configration of TeamsAPI +// TeamsAPIConfiguration defines the configuration of TeamsAPI type TeamsAPIConfiguration struct { EnableTeamsAPI bool `json:"enable_teams_api,omitempty"` TeamsAPIUrl string `json:"teams_api_url,omitempty"` @@ -150,6 +150,17 @@ type ScalyrConfiguration struct { ScalyrMemoryLimit string `json:"scalyr_memory_limit,omitempty"` } +// OperatorLogicalBackupConfiguration defines configuration for logical backup +type OperatorLogicalBackupConfiguration struct { + Schedule string `json:"logical_backup_schedule,omitempty"` + DockerImage string `json:"logical_backup_docker_image,omitempty"` + S3Bucket string `json:"logical_backup_s3_bucket,omitempty"` + S3Endpoint string `json:"logical_backup_s3_endpoint,omitempty"` + S3AccessKeyID string `json:"logical_backup_s3_access_key_id,omitempty"` + S3SecretAccessKey string `json:"logical_backup_s3_secret_access_key,omitempty"` + S3SSE string `json:"logical_backup_s3_sse,omitempty"` +} + // OperatorConfigurationData defines the operation config type OperatorConfigurationData struct { EnableCRDValidation *bool `json:"enable_crd_validation,omitempty"` @@ -176,24 +187,5 @@ type OperatorConfigurationData struct { LogicalBackup OperatorLogicalBackupConfiguration `json:"logical_backup"` } -// OperatorConfigurationUsers defines configration for super user -type OperatorConfigurationUsers struct { - SuperUserName string `json:"superuser_name,omitempty"` - Replication string `json:"replication_user_name,omitempty"` - ProtectedRoles []string `json:"protected_roles,omitempty"` - TeamAPIRoleConfiguration map[string]string `json:"team_api_role_configuration,omitempty"` -} - //Duration shortens this frequently used name type Duration time.Duration - -// OperatorLogicalBackupConfiguration defines configration for logical backup -type OperatorLogicalBackupConfiguration struct { - Schedule string `json:"logical_backup_schedule,omitempty"` - DockerImage string `json:"logical_backup_docker_image,omitempty"` - S3Bucket string `json:"logical_backup_s3_bucket,omitempty"` - S3Endpoint string `json:"logical_backup_s3_endpoint,omitempty"` - S3AccessKeyID string `json:"logical_backup_s3_access_key_id,omitempty"` - S3SecretAccessKey string `json:"logical_backup_s3_secret_access_key,omitempty"` - S3SSE string `json:"logical_backup_s3_sse,omitempty"` -} diff --git a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go index 16f5a9d67..b68a72d1f 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -300,34 +300,6 @@ func (in *OperatorConfigurationList) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OperatorConfigurationUsers) DeepCopyInto(out *OperatorConfigurationUsers) { - *out = *in - if in.ProtectedRoles != nil { - in, out := &in.ProtectedRoles, &out.ProtectedRoles - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.TeamAPIRoleConfiguration != nil { - in, out := &in.TeamAPIRoleConfiguration, &out.TeamAPIRoleConfiguration - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConfigurationUsers. -func (in *OperatorConfigurationUsers) DeepCopy() *OperatorConfigurationUsers { - if in == nil { - return nil - } - out := new(OperatorConfigurationUsers) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OperatorDebugConfiguration) DeepCopyInto(out *OperatorDebugConfiguration) { *out = *in diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index d46cba2b2..b2a135fad 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -69,7 +69,7 @@ type Scalyr struct { ScalyrMemoryLimit string `name:"scalyr_memory_limit" default:"1Gi"` } -// LogicalBackup defines configration for logical backup +// LogicalBackup defines configuration for logical backup type LogicalBackup struct { LogicalBackupSchedule string `name:"logical_backup_schedule" default:"30 00 * * *"` LogicalBackupDockerImage string `name:"logical_backup_docker_image" default:"registry.opensource.zalan.do/acid/logical-backup"` From 7af1de890cbadb02e92d167492d9a02a45ab0a14 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Tue, 17 Dec 2019 17:13:56 +0100 Subject: [PATCH 21/21] bump operator v1.3.0 with Spilo 12 image (#770) --- charts/postgres-operator/Chart.yaml | 6 ++-- charts/postgres-operator/index.yaml | 27 ++++++++++++++++-- .../postgres-operator-1.3.0.tgz | Bin 0 -> 19063 bytes charts/postgres-operator/values-crd.yaml | 4 +-- charts/postgres-operator/values.yaml | 4 +-- manifests/complete-postgres-manifest.yaml | 2 +- manifests/configmap.yaml | 2 +- manifests/postgres-operator.yaml | 2 +- ...gresql-operator-default-configuration.yaml | 2 +- pkg/util/config/config.go | 2 +- 10 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 charts/postgres-operator/postgres-operator-1.3.0.tgz diff --git a/charts/postgres-operator/Chart.yaml b/charts/postgres-operator/Chart.yaml index ae9bb855e..08e242a53 100644 --- a/charts/postgres-operator/Chart.yaml +++ b/charts/postgres-operator/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v1 name: postgres-operator -version: 1.2.0 -appVersion: 1.2.0 +version: 1.3.0 +appVersion: 1.3.0 home: https://github.com/zalando/postgres-operator description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes keywords: @@ -13,8 +13,6 @@ keywords: maintainers: - name: Zalando email: opensource@zalando.de -- name: kimxogus - email: kgyoo8232@gmail.com sources: - https://github.com/zalando/postgres-operator engine: gotpl diff --git a/charts/postgres-operator/index.yaml b/charts/postgres-operator/index.yaml index b549f1220..84502f6a6 100644 --- a/charts/postgres-operator/index.yaml +++ b/charts/postgres-operator/index.yaml @@ -1,13 +1,34 @@ apiVersion: v1 entries: postgres-operator: + - apiVersion: v1 + appVersion: 1.3.0 + created: "2019-12-17T12:58:49.477140129+01:00" + description: Postgres Operator creates and manages PostgreSQL clusters running + in Kubernetes + digest: 7e788fd37daec76a01f6d6f9fe5be5b54f5035e4eba0041e80a760d656537325 + home: https://github.com/zalando/postgres-operator + keywords: + - postgres + - operator + - cloud-native + - patroni + - spilo + maintainers: + - email: opensource@zalando.de + name: Zalando + name: postgres-operator + sources: + - https://github.com/zalando/postgres-operator + urls: + - postgres-operator-1.3.0.tgz + version: 1.3.0 - apiVersion: v1 appVersion: 1.2.0 - created: "2019-08-13T17:33:32.735021423+02:00" + created: "2019-12-17T12:58:49.475844233+01:00" description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes digest: d10710c7cf19f4e266e7704f5d1e98dcfc61bee3919522326c35c22ca7d2f2bf - engine: gotpl home: https://github.com/zalando/postgres-operator keywords: - postgres @@ -26,4 +47,4 @@ entries: urls: - postgres-operator-1.2.0.tgz version: 1.2.0 -generated: "2019-08-13T17:33:32.734335398+02:00" +generated: "2019-12-17T12:58:49.474719294+01:00" diff --git a/charts/postgres-operator/postgres-operator-1.3.0.tgz b/charts/postgres-operator/postgres-operator-1.3.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..460fed53286e21075290ed1d7cdcc1778100f95c GIT binary patch literal 19063 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