From 010865f5d9fb901f5bf6fac29d856cf9cfac79d0 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 12 Jan 2021 15:39:54 +0100 Subject: [PATCH 01/26] Fix typo in operatorconfigurations CRD (#1305) * fix typo in operatorconfigurations crd * fix typo in operatorconfigurations manifest --- charts/postgres-operator/crds/operatorconfigurations.yaml | 2 +- manifests/operatorconfiguration.crd.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index 09c29002c..a360da0c6 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -457,7 +457,7 @@ spec: log_statement: all teams_api_url: type: string - defaults: "https://teams.example.com/api/" + default: "https://teams.example.com/api/" logging_rest_api: type: object properties: diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index cc8dbb6cc..7add1b8c6 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -453,7 +453,7 @@ spec: log_statement: all teams_api_url: type: string - defaults: "https://teams.example.com/api/" + default: "https://teams.example.com/api/" logging_rest_api: type: object properties: From ff46bb069bbe9efe7bb9956f2953e64c0ab5f02b Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Wed, 13 Jan 2021 10:40:55 +0100 Subject: [PATCH 02/26] update docker base images and UI dependencies (#1302) * update docker base images and UI dependencies * use latest compliant base image --- docker/DebugDockerfile | 2 +- docker/Dockerfile | 2 +- docker/logical-backup/Dockerfile | 2 +- ui/Dockerfile | 2 +- ui/requirements.txt | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docker/DebugDockerfile b/docker/DebugDockerfile index 0bfe9a277..e8f51badd 100644 --- a/docker/DebugDockerfile +++ b/docker/DebugDockerfile @@ -1,4 +1,4 @@ -FROM alpine +FROM registry.opensource.zalan.do/library/alpine-3.12:latest LABEL maintainer="Team ACID @ Zalando " # We need root certificates to deal with teams api over https diff --git a/docker/Dockerfile b/docker/Dockerfile index bf844850f..c1b87caf7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine +FROM registry.opensource.zalan.do/library/alpine-3.12:latest LABEL maintainer="Team ACID @ Zalando " # We need root certificates to deal with teams api over https diff --git a/docker/logical-backup/Dockerfile b/docker/logical-backup/Dockerfile index c8bbe6f28..b84ea2b22 100644 --- a/docker/logical-backup/Dockerfile +++ b/docker/logical-backup/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.04 +FROM registry.opensource.zalan.do/library/ubuntu-18.04:latest LABEL maintainer="Team ACID @ Zalando " SHELL ["/bin/bash", "-o", "pipefail", "-c"] diff --git a/ui/Dockerfile b/ui/Dockerfile index 9384f90db..ad775ece2 100644 --- a/ui/Dockerfile +++ b/ui/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.6 +FROM registry.opensource.zalan.do/library/alpine-3.12:latest LABEL maintainer="Team ACID @ Zalando " EXPOSE 8081 diff --git a/ui/requirements.txt b/ui/requirements.txt index 7dc49eb3d..8f612d554 100644 --- a/ui/requirements.txt +++ b/ui/requirements.txt @@ -1,15 +1,15 @@ Flask-OAuthlib==0.9.5 Flask==1.1.2 -backoff==1.8.1 -boto3==1.10.4 +backoff==1.10.0 +boto3==1.16.52 boto==2.49.0 -click==6.7 -furl==1.0.2 -gevent==1.2.2 -jq==0.1.6 +click==7.1.2 +furl==2.1.0 +gevent==20.12.1 +jq==1.1.1 json_delta>=2.0 kubernetes==3.0.0 -requests==2.22.0 +requests==2.25.1 stups-tokens>=1.1.19 -wal_e==1.1.0 +wal_e==1.1.1 werkzeug==0.16.1 From e398cf8c7e7553d00a796cb278e2d22542ba2345 Mon Sep 17 00:00:00 2001 From: Rafia Sabih Date: Thu, 14 Jan 2021 09:53:09 +0100 Subject: [PATCH 03/26] Avoid syncing when possible (#1274) Avoid extra syncing in case there are no changes in pooler requirements. Add pooler specific labels to pooler secrets. Add test case to check for pooler secret creation and deletion. Co-authored-by: Rafia Sabih --- e2e/README.md | 2 +- e2e/tests/test_e2e.py | 12 ++++++++-- pkg/cluster/connection_pooler.go | 40 ++++++++++++++++++++++++++++---- pkg/cluster/k8sres.go | 9 ++++++- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/e2e/README.md b/e2e/README.md index 3bba6ccc3..5aa987593 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -44,7 +44,7 @@ To run the end 2 end test and keep the kind state execute: NOCLEANUP=True ./run.sh main ``` -## Run indidual test +## Run individual test After having executed a normal E2E run with `NOCLEANUP=True` Kind still continues to run, allowing you subsequent test runs. diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 9e2035652..ecc0b2327 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -160,7 +160,7 @@ class EndToEndTestCase(unittest.TestCase): self.k8s.create_with_kubectl("manifests/minimal-fake-pooler-deployment.yaml") self.eventuallyEqual(lambda: self.k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") self.eventuallyEqual(lambda: self.k8s.get_deployment_replica_count(name="acid-minimal-cluster-pooler"), 1, - "Initial broken deplyment not rolled out") + "Initial broken deployment not rolled out") self.k8s.api.custom_objects_api.patch_namespaced_custom_object( 'acid.zalan.do', 'v1', 'default', @@ -221,6 +221,8 @@ class EndToEndTestCase(unittest.TestCase): self.eventuallyEqual(lambda: k8s.count_services_with_label( 'application=db-connection-pooler,cluster-name=acid-minimal-cluster'), 2, "No pooler service found") + self.eventuallyEqual(lambda: k8s.count_secrets_with_label('application=db-connection-pooler,cluster-name=acid-minimal-cluster'), + 1, "Pooler secret not created") # Turn off only master connection pooler k8s.api.custom_objects_api.patch_namespaced_custom_object( @@ -246,6 +248,8 @@ class EndToEndTestCase(unittest.TestCase): self.eventuallyEqual(lambda: k8s.count_services_with_label( 'application=db-connection-pooler,cluster-name=acid-minimal-cluster'), 1, "No pooler service found") + self.eventuallyEqual(lambda: k8s.count_secrets_with_label('application=db-connection-pooler,cluster-name=acid-minimal-cluster'), + 1, "Secret not created") # Turn off only replica connection pooler k8s.api.custom_objects_api.patch_namespaced_custom_object( @@ -268,6 +272,8 @@ class EndToEndTestCase(unittest.TestCase): 0, "Pooler replica pods not deleted") self.eventuallyEqual(lambda: k8s.count_services_with_label('application=db-connection-pooler,cluster-name=acid-minimal-cluster'), 1, "No pooler service found") + self.eventuallyEqual(lambda: k8s.count_secrets_with_label('application=db-connection-pooler,cluster-name=acid-minimal-cluster'), + 1, "Secret not created") # scale up connection pooler deployment k8s.api.custom_objects_api.patch_namespaced_custom_object( @@ -301,6 +307,8 @@ class EndToEndTestCase(unittest.TestCase): 0, "Pooler pods not scaled down") self.eventuallyEqual(lambda: k8s.count_services_with_label('application=db-connection-pooler,cluster-name=acid-minimal-cluster'), 0, "Pooler service not removed") + self.eventuallyEqual(lambda: k8s.count_secrets_with_label('application=spilo,cluster-name=acid-minimal-cluster'), + 4, "Secrets not deleted") # Verify that all the databases have pooler schema installed. # Do this via psql, since otherwise we need to deal with @@ -1034,7 +1042,7 @@ class EndToEndTestCase(unittest.TestCase): except timeout_decorator.TimeoutError: print('Operator log: {}'.format(k8s.get_operator_log())) raise - + @timeout_decorator.timeout(TEST_TIMEOUT_SEC) def test_zzzz_cluster_deletion(self): ''' diff --git a/pkg/cluster/connection_pooler.go b/pkg/cluster/connection_pooler.go index 1d1d609e4..e6cc60cb2 100644 --- a/pkg/cluster/connection_pooler.go +++ b/pkg/cluster/connection_pooler.go @@ -539,13 +539,13 @@ func updateConnectionPoolerAnnotations(KubeClient k8sutil.KubernetesClient, depl // Test if two connection pooler configuration needs to be synced. For simplicity // compare not the actual K8S objects, but the configuration itself and request // sync if there is any difference. -func needSyncConnectionPoolerSpecs(oldSpec, newSpec *acidv1.ConnectionPooler) (sync bool, reasons []string) { +func needSyncConnectionPoolerSpecs(oldSpec, newSpec *acidv1.ConnectionPooler, logger *logrus.Entry) (sync bool, reasons []string) { reasons = []string{} sync = false changelog, err := diff.Diff(oldSpec, newSpec) if err != nil { - //c.logger.Infof("Cannot get diff, do not do anything, %+v", err) + logger.Infof("cannot get diff, do not do anything, %+v", err) return false, reasons } @@ -681,13 +681,45 @@ func logPoolerEssentials(log *logrus.Entry, oldSpec, newSpec *acidv1.Postgresql) } func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, LookupFunction InstallFunction) (SyncReason, error) { - logPoolerEssentials(c.logger, oldSpec, newSpec) var reason SyncReason var err error var newNeedConnectionPooler, oldNeedConnectionPooler bool oldNeedConnectionPooler = false + if oldSpec == nil { + oldSpec = &acidv1.Postgresql{ + Spec: acidv1.PostgresSpec{ + ConnectionPooler: &acidv1.ConnectionPooler{}, + }, + } + } + + needSync, _ := needSyncConnectionPoolerSpecs(oldSpec.Spec.ConnectionPooler, newSpec.Spec.ConnectionPooler, c.logger) + masterChanges, err := diff.Diff(oldSpec.Spec.EnableConnectionPooler, newSpec.Spec.EnableConnectionPooler) + if err != nil { + c.logger.Error("Error in getting diff of master connection pooler changes") + } + replicaChanges, err := diff.Diff(oldSpec.Spec.EnableReplicaConnectionPooler, newSpec.Spec.EnableReplicaConnectionPooler) + if err != nil { + c.logger.Error("Error in getting diff of replica connection pooler changes") + } + + // skip pooler sync only + // 1. if there is no diff in spec, AND + // 2. if connection pooler is already there and is also required as per newSpec + // + // Handling the case when connectionPooler is not there but it is required + // as per spec, hence do not skip syncing in that case, even though there + // is no diff in specs + if (!needSync && len(masterChanges) <= 0 && len(replicaChanges) <= 0) && + (c.ConnectionPooler != nil && *newSpec.Spec.EnableConnectionPooler) { + c.logger.Debugln("syncing pooler is not required") + return nil, nil + } + + logPoolerEssentials(c.logger, oldSpec, newSpec) + // Check and perform the sync requirements for each of the roles. for _, role := range [2]PostgresRole{Master, Replica} { @@ -841,7 +873,7 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql var specReason []string if oldSpec != nil { - specSync, specReason = needSyncConnectionPoolerSpecs(oldConnectionPooler, newConnectionPooler) + specSync, specReason = needSyncConnectionPoolerSpecs(oldConnectionPooler, newConnectionPooler, c.logger) } defaultsSync, defaultsReason := needSyncConnectionPoolerDefaults(&c.Config, newConnectionPooler, deployment) diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 6b1af045f..06b074b4c 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -1561,11 +1561,17 @@ func (c *Cluster) generateSingleUserSecret(namespace string, pgUser spec.PgUser) } username := pgUser.Name + lbls := c.labelsSet(true) + + if username == constants.ConnectionPoolerUserName { + lbls = c.connectionPoolerLabels("", false).MatchLabels + } + secret := v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: c.credentialSecretName(username), Namespace: namespace, - Labels: c.labelsSet(true), + Labels: lbls, Annotations: c.annotationsSet(nil), }, Type: v1.SecretTypeOpaque, @@ -1574,6 +1580,7 @@ func (c *Cluster) generateSingleUserSecret(namespace string, pgUser spec.PgUser) "password": []byte(pgUser.Password), }, } + return &secret } From 258799b420e4c2193b8fa3afd6f3f9113fa952a1 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Fri, 15 Jan 2021 15:11:02 +0100 Subject: [PATCH 04/26] allow additional members from other teams (#1314) --- pkg/cluster/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cluster/util.go b/pkg/cluster/util.go index d5e887656..393a490bd 100644 --- a/pkg/cluster/util.go +++ b/pkg/cluster/util.go @@ -240,7 +240,7 @@ func (c *Cluster) getTeamMembers(teamID string) ([]string, error) { c.logger.Debugf("fetching possible additional team members for team %q", teamID) members := []string{} - additionalMembers := c.PgTeamMap[c.Spec.TeamID].AdditionalMembers + additionalMembers := c.PgTeamMap[teamID].AdditionalMembers for _, member := range additionalMembers { members = append(members, member) } From 2b45478f3ac00e74036b7a43e5de3ab83aff0c23 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Tue, 19 Jan 2021 10:47:32 +0100 Subject: [PATCH 05/26] add host info to connection docs (#1319) --- docs/user.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/user.md b/docs/user.md index 3463983f7..ec5941d9e 100644 --- a/docs/user.md +++ b/docs/user.md @@ -71,26 +71,26 @@ kubectl describe postgresql acid-minimal-cluster ## Connect to PostgreSQL With a `port-forward` on one of the database pods (e.g. the master) you can -connect to the PostgreSQL database. Use labels to filter for the master pod of -our test cluster. +connect to the PostgreSQL database from your machine. Use labels to filter for +the master pod of our test cluster. ```bash # get name of master pod of acid-minimal-cluster -export PGMASTER=$(kubectl get pods -o jsonpath={.items..metadata.name} -l application=spilo,cluster-name=acid-minimal-cluster,spilo-role=master) +export PGMASTER=$(kubectl get pods -o jsonpath={.items..metadata.name} -l application=spilo,cluster-name=acid-minimal-cluster,spilo-role=master -n default) # set up port forward -kubectl port-forward $PGMASTER 6432:5432 +kubectl port-forward $PGMASTER 6432:5432 -n default ``` -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. As non-encrypted connections are rejected by default set the SSL -mode to require: +Open another CLI and connect to the database using e.g. the psql client. +When connecting with the `postgres` user read its password from the K8s secret +which was generated when creating the `acid-minimal-cluster`. 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 +psql -U postgres -h localhost -p 6432 ``` ## Defining database roles in the operator From a9b677c957be09de5e02f3b0eec4221c551eb2ca Mon Sep 17 00:00:00 2001 From: Rafia Sabih Date: Tue, 19 Jan 2021 17:40:20 +0100 Subject: [PATCH 06/26] Use fake client for connection pooler (#1301) Connection pooler creation, deletion, and synchronization now tested using fake client API. Co-authored-by: Rafia Sabih --- pkg/cluster/connection_pooler.go | 2 +- pkg/cluster/connection_pooler_test.go | 540 ++++++++++++++------------ 2 files changed, 297 insertions(+), 245 deletions(-) diff --git a/pkg/cluster/connection_pooler.go b/pkg/cluster/connection_pooler.go index e6cc60cb2..2e3f04876 100644 --- a/pkg/cluster/connection_pooler.go +++ b/pkg/cluster/connection_pooler.go @@ -713,7 +713,7 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look // as per spec, hence do not skip syncing in that case, even though there // is no diff in specs if (!needSync && len(masterChanges) <= 0 && len(replicaChanges) <= 0) && - (c.ConnectionPooler != nil && *newSpec.Spec.EnableConnectionPooler) { + (c.ConnectionPooler != nil && (needConnectionPooler(&newSpec.Spec))) { c.logger.Debugln("syncing pooler is not required") return nil, nil } diff --git a/pkg/cluster/connection_pooler_test.go b/pkg/cluster/connection_pooler_test.go index 54be0f5bd..280adb101 100644 --- a/pkg/cluster/connection_pooler_test.go +++ b/pkg/cluster/connection_pooler_test.go @@ -6,13 +6,17 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" + fakeacidv1 "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/fake" + "github.com/zalando/postgres-operator/pkg/util" "github.com/zalando/postgres-operator/pkg/util/config" "github.com/zalando/postgres-operator/pkg/util/k8sutil" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" ) func mockInstallLookupFunction(schema string, user string, role PostgresRole) error { @@ -27,79 +31,122 @@ func int32ToPointer(value int32) *int32 { return &value } -func TestConnectionPoolerCreationAndDeletion(t *testing.T) { - testName := "Test connection pooler creation" - var cluster = New( - Config{ - OpConfig: config.Config{ - ProtectedRoles: []string{"admin"}, - Auth: config.Auth{ - SuperUsername: superUserName, - ReplicationUsername: replicationUserName, - }, - ConnectionPooler: config.ConnectionPooler{ - ConnectionPoolerDefaultCPURequest: "100m", - ConnectionPoolerDefaultCPULimit: "100m", - ConnectionPoolerDefaultMemoryRequest: "100Mi", - ConnectionPoolerDefaultMemoryLimit: "100Mi", - NumberOfInstances: int32ToPointer(1), - }, - }, - }, k8sutil.NewMockKubernetesClient(), acidv1.Postgresql{}, logger, eventRecorder) - - cluster.Statefulset = &appsv1.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-sts", - }, - } - - cluster.Spec = acidv1.PostgresSpec{ - ConnectionPooler: &acidv1.ConnectionPooler{}, - EnableReplicaConnectionPooler: boolToPointer(true), - } - - reason, err := cluster.createConnectionPooler(mockInstallLookupFunction) - - if err != nil { - t.Errorf("%s: Cannot create connection pooler, %s, %+v", - testName, err, reason) - } +func deploymentUpdated(cluster *Cluster, err error, reason SyncReason) error { for _, role := range [2]PostgresRole{Master, Replica} { - if cluster.ConnectionPooler[role] != nil { - if cluster.ConnectionPooler[role].Deployment == nil { - t.Errorf("%s: Connection pooler deployment is empty for role %s", testName, role) - } - if cluster.ConnectionPooler[role].Service == nil { - t.Errorf("%s: Connection pooler service is empty for role %s", testName, role) - } + poolerLabels := cluster.labelsSet(false) + poolerLabels["application"] = "db-connection-pooler" + poolerLabels["connection-pooler"] = cluster.connectionPoolerName(role) + + if cluster.ConnectionPooler[role] != nil && cluster.ConnectionPooler[role].Deployment != nil && + util.MapContains(cluster.ConnectionPooler[role].Deployment.Labels, poolerLabels) && + (cluster.ConnectionPooler[role].Deployment.Spec.Replicas == nil || + *cluster.ConnectionPooler[role].Deployment.Spec.Replicas != 2) { + return fmt.Errorf("Wrong number of instances") } } - oldSpec := &acidv1.Postgresql{ - Spec: acidv1.PostgresSpec{ - EnableConnectionPooler: boolToPointer(true), - EnableReplicaConnectionPooler: boolToPointer(true), - }, - } - newSpec := &acidv1.Postgresql{ - Spec: acidv1.PostgresSpec{ - EnableConnectionPooler: boolToPointer(false), - EnableReplicaConnectionPooler: boolToPointer(false), - }, + return nil +} + +func objectsAreSaved(cluster *Cluster, err error, reason SyncReason) error { + if cluster.ConnectionPooler == nil { + return fmt.Errorf("Connection pooler resources are empty") } - // Delete connection pooler via sync - _, err = cluster.syncConnectionPooler(oldSpec, newSpec, mockInstallLookupFunction) - if err != nil { - t.Errorf("%s: Cannot sync connection pooler, %s", testName, err) - } + for _, role := range []PostgresRole{Master, Replica} { + poolerLabels := cluster.labelsSet(false) + poolerLabels["application"] = "db-connection-pooler" + poolerLabels["connection-pooler"] = cluster.connectionPoolerName(role) - for _, role := range [2]PostgresRole{Master, Replica} { - err = cluster.deleteConnectionPooler(role) - if err != nil { - t.Errorf("%s: Cannot delete connection pooler, %s", testName, err) + if cluster.ConnectionPooler[role].Deployment == nil || !util.MapContains(cluster.ConnectionPooler[role].Deployment.Labels, poolerLabels) { + return fmt.Errorf("Deployment was not saved or labels not attached %s %s", role, cluster.ConnectionPooler[role].Deployment.Labels) + } + + if cluster.ConnectionPooler[role].Service == nil || !util.MapContains(cluster.ConnectionPooler[role].Service.Labels, poolerLabels) { + return fmt.Errorf("Service was not saved or labels not attached %s %s", role, cluster.ConnectionPooler[role].Service.Labels) } } + + return nil +} + +func MasterObjectsAreSaved(cluster *Cluster, err error, reason SyncReason) error { + if cluster.ConnectionPooler == nil { + return fmt.Errorf("Connection pooler resources are empty") + } + + poolerLabels := cluster.labelsSet(false) + poolerLabels["application"] = "db-connection-pooler" + poolerLabels["connection-pooler"] = cluster.connectionPoolerName(Master) + + if cluster.ConnectionPooler[Master].Deployment == nil || !util.MapContains(cluster.ConnectionPooler[Master].Deployment.Labels, poolerLabels) { + return fmt.Errorf("Deployment was not saved or labels not attached %s", cluster.ConnectionPooler[Master].Deployment.Labels) + } + + if cluster.ConnectionPooler[Master].Service == nil || !util.MapContains(cluster.ConnectionPooler[Master].Service.Labels, poolerLabels) { + return fmt.Errorf("Service was not saved or labels not attached %s", cluster.ConnectionPooler[Master].Service.Labels) + } + + return nil +} + +func ReplicaObjectsAreSaved(cluster *Cluster, err error, reason SyncReason) error { + if cluster.ConnectionPooler == nil { + return fmt.Errorf("Connection pooler resources are empty") + } + + poolerLabels := cluster.labelsSet(false) + poolerLabels["application"] = "db-connection-pooler" + poolerLabels["connection-pooler"] = cluster.connectionPoolerName(Replica) + + if cluster.ConnectionPooler[Replica].Deployment == nil || !util.MapContains(cluster.ConnectionPooler[Replica].Deployment.Labels, poolerLabels) { + return fmt.Errorf("Deployment was not saved or labels not attached %s", cluster.ConnectionPooler[Replica].Deployment.Labels) + } + + if cluster.ConnectionPooler[Replica].Service == nil || !util.MapContains(cluster.ConnectionPooler[Replica].Service.Labels, poolerLabels) { + return fmt.Errorf("Service was not saved or labels not attached %s", cluster.ConnectionPooler[Replica].Service.Labels) + } + + return nil +} + +func objectsAreDeleted(cluster *Cluster, err error, reason SyncReason) error { + for _, role := range [2]PostgresRole{Master, Replica} { + if cluster.ConnectionPooler[role] != nil && + (cluster.ConnectionPooler[role].Deployment != nil || cluster.ConnectionPooler[role].Service != nil) { + return fmt.Errorf("Connection pooler was not deleted for role %v", role) + } + } + + return nil +} + +func OnlyMasterDeleted(cluster *Cluster, err error, reason SyncReason) error { + + if cluster.ConnectionPooler[Master] != nil && + (cluster.ConnectionPooler[Master].Deployment != nil || cluster.ConnectionPooler[Master].Service != nil) { + return fmt.Errorf("Connection pooler master was not deleted") + } + return nil +} + +func OnlyReplicaDeleted(cluster *Cluster, err error, reason SyncReason) error { + + if cluster.ConnectionPooler[Replica] != nil && + (cluster.ConnectionPooler[Replica].Deployment != nil || cluster.ConnectionPooler[Replica].Service != nil) { + return fmt.Errorf("Connection pooler replica was not deleted") + } + return nil +} + +func noEmptySync(cluster *Cluster, err error, reason SyncReason) error { + for _, msg := range reason { + if strings.HasPrefix(msg, "update [] from '' to '") { + return fmt.Errorf("There is an empty reason, %s", msg) + } + } + + return nil } func TestNeedConnectionPooler(t *testing.T) { @@ -210,133 +257,178 @@ func TestNeedConnectionPooler(t *testing.T) { } } -func deploymentUpdated(cluster *Cluster, err error, reason SyncReason) error { - for _, role := range [2]PostgresRole{Master, Replica} { - if cluster.ConnectionPooler[role] != nil && cluster.ConnectionPooler[role].Deployment != nil && - (cluster.ConnectionPooler[role].Deployment.Spec.Replicas == nil || - *cluster.ConnectionPooler[role].Deployment.Spec.Replicas != 2) { - return fmt.Errorf("Wrong number of instances") - } - } - return nil -} +func TestConnectionPoolerCreateDeletion(t *testing.T) { -func objectsAreSaved(cluster *Cluster, err error, reason SyncReason) error { - if cluster.ConnectionPooler == nil { - return fmt.Errorf("Connection pooler resources are empty") + testName := "test connection pooler creation and deletion" + clientSet := fake.NewSimpleClientset() + acidClientSet := fakeacidv1.NewSimpleClientset() + namespace := "default" + + client := k8sutil.KubernetesClient{ + StatefulSetsGetter: clientSet.AppsV1(), + ServicesGetter: clientSet.CoreV1(), + DeploymentsGetter: clientSet.AppsV1(), + PostgresqlsGetter: acidClientSet.AcidV1(), + SecretsGetter: clientSet.CoreV1(), } - for _, role := range []PostgresRole{Master, Replica} { - if cluster.ConnectionPooler[role].Deployment == nil { - return fmt.Errorf("Deployment was not saved %s", role) - } - - if cluster.ConnectionPooler[role].Service == nil { - return fmt.Errorf("Service was not saved %s", role) - } - } - - return nil -} - -func MasterobjectsAreSaved(cluster *Cluster, err error, reason SyncReason) error { - if cluster.ConnectionPooler == nil { - return fmt.Errorf("Connection pooler resources are empty") - } - - if cluster.ConnectionPooler[Master].Deployment == nil { - return fmt.Errorf("Deployment was not saved") - } - - if cluster.ConnectionPooler[Master].Service == nil { - return fmt.Errorf("Service was not saved") - } - - return nil -} - -func ReplicaobjectsAreSaved(cluster *Cluster, err error, reason SyncReason) error { - if cluster.ConnectionPooler == nil { - return fmt.Errorf("Connection pooler resources are empty") - } - - if cluster.ConnectionPooler[Replica].Deployment == nil { - return fmt.Errorf("Deployment was not saved") - } - - if cluster.ConnectionPooler[Replica].Service == nil { - return fmt.Errorf("Service was not saved") - } - - return nil -} - -func objectsAreDeleted(cluster *Cluster, err error, reason SyncReason) error { - for _, role := range [2]PostgresRole{Master, Replica} { - if cluster.ConnectionPooler[role] != nil && - (cluster.ConnectionPooler[role].Deployment != nil || cluster.ConnectionPooler[role].Service != nil) { - return fmt.Errorf("Connection pooler was not deleted for role %v", role) - } - } - - return nil -} - -func OnlyMasterDeleted(cluster *Cluster, err error, reason SyncReason) error { - - if cluster.ConnectionPooler[Master] != nil && - (cluster.ConnectionPooler[Master].Deployment != nil || cluster.ConnectionPooler[Master].Service != nil) { - return fmt.Errorf("Connection pooler master was not deleted") - } - return nil -} - -func OnlyReplicaDeleted(cluster *Cluster, err error, reason SyncReason) error { - - if cluster.ConnectionPooler[Replica] != nil && - (cluster.ConnectionPooler[Replica].Deployment != nil || cluster.ConnectionPooler[Replica].Service != nil) { - return fmt.Errorf("Connection pooler replica was not deleted") - } - return nil -} - -func noEmptySync(cluster *Cluster, err error, reason SyncReason) error { - for _, msg := range reason { - if strings.HasPrefix(msg, "update [] from '' to '") { - return fmt.Errorf("There is an empty reason, %s", msg) - } - } - - return nil -} - -func TestConnectionPoolerSynchronization(t *testing.T) { - testName := "Test connection pooler synchronization" - newCluster := func(client k8sutil.KubernetesClient) *Cluster { - return New( - Config{ - OpConfig: config.Config{ - ProtectedRoles: []string{"admin"}, - Auth: config.Auth{ - SuperUsername: superUserName, - ReplicationUsername: replicationUserName, - }, - ConnectionPooler: config.ConnectionPooler{ - ConnectionPoolerDefaultCPURequest: "100m", - ConnectionPoolerDefaultCPULimit: "100m", - ConnectionPoolerDefaultMemoryRequest: "100Mi", - ConnectionPoolerDefaultMemoryLimit: "100Mi", - NumberOfInstances: int32ToPointer(1), - }, - }, - }, client, acidv1.Postgresql{}, logger, eventRecorder) - } - cluster := newCluster(k8sutil.KubernetesClient{}) - - cluster.Statefulset = &appsv1.StatefulSet{ + pg := acidv1.Postgresql{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-sts", + Name: "acid-fake-cluster", + Namespace: namespace, }, + Spec: acidv1.PostgresSpec{ + EnableConnectionPooler: boolToPointer(true), + EnableReplicaConnectionPooler: boolToPointer(true), + Volume: acidv1.Volume{ + Size: "1Gi", + }, + }, + } + + var cluster = New( + Config{ + OpConfig: config.Config{ + ConnectionPooler: config.ConnectionPooler{ + ConnectionPoolerDefaultCPURequest: "100m", + ConnectionPoolerDefaultCPULimit: "100m", + ConnectionPoolerDefaultMemoryRequest: "100Mi", + ConnectionPoolerDefaultMemoryLimit: "100Mi", + NumberOfInstances: int32ToPointer(1), + }, + PodManagementPolicy: "ordered_ready", + Resources: config.Resources{ + ClusterLabels: map[string]string{"application": "spilo"}, + ClusterNameLabel: "cluster-name", + DefaultCPURequest: "300m", + DefaultCPULimit: "300m", + DefaultMemoryRequest: "300Mi", + DefaultMemoryLimit: "300Mi", + PodRoleLabel: "spilo-role", + }, + }, + }, client, pg, logger, eventRecorder) + + cluster.Name = "acid-fake-cluster" + cluster.Namespace = "default" + + _, err := cluster.createService(Master) + assert.NoError(t, err) + _, err = cluster.createStatefulSet() + assert.NoError(t, err) + + reason, err := cluster.createConnectionPooler(mockInstallLookupFunction) + + if err != nil { + t.Errorf("%s: Cannot create connection pooler, %s, %+v", + testName, err, reason) + } + for _, role := range [2]PostgresRole{Master, Replica} { + poolerLabels := cluster.labelsSet(false) + poolerLabels["application"] = "db-connection-pooler" + poolerLabels["connection-pooler"] = cluster.connectionPoolerName(role) + + if cluster.ConnectionPooler[role] != nil { + if cluster.ConnectionPooler[role].Deployment == nil && util.MapContains(cluster.ConnectionPooler[role].Deployment.Labels, poolerLabels) { + t.Errorf("%s: Connection pooler deployment is empty for role %s", testName, role) + } + + if cluster.ConnectionPooler[role].Service == nil && util.MapContains(cluster.ConnectionPooler[role].Service.Labels, poolerLabels) { + t.Errorf("%s: Connection pooler service is empty for role %s", testName, role) + } + } + } + + oldSpec := &acidv1.Postgresql{ + Spec: acidv1.PostgresSpec{ + EnableConnectionPooler: boolToPointer(true), + EnableReplicaConnectionPooler: boolToPointer(true), + }, + } + newSpec := &acidv1.Postgresql{ + Spec: acidv1.PostgresSpec{ + EnableConnectionPooler: boolToPointer(false), + EnableReplicaConnectionPooler: boolToPointer(false), + }, + } + + // Delete connection pooler via sync + _, err = cluster.syncConnectionPooler(oldSpec, newSpec, mockInstallLookupFunction) + if err != nil { + t.Errorf("%s: Cannot sync connection pooler, %s", testName, err) + } + + for _, role := range [2]PostgresRole{Master, Replica} { + err = cluster.deleteConnectionPooler(role) + if err != nil { + t.Errorf("%s: Cannot delete connection pooler, %s", testName, err) + } + } +} + +func TestConnectionPoolerSync(t *testing.T) { + + testName := "test connection pooler synchronization" + clientSet := fake.NewSimpleClientset() + acidClientSet := fakeacidv1.NewSimpleClientset() + namespace := "default" + + client := k8sutil.KubernetesClient{ + StatefulSetsGetter: clientSet.AppsV1(), + ServicesGetter: clientSet.CoreV1(), + DeploymentsGetter: clientSet.AppsV1(), + PostgresqlsGetter: acidClientSet.AcidV1(), + SecretsGetter: clientSet.CoreV1(), + } + + pg := acidv1.Postgresql{ + ObjectMeta: metav1.ObjectMeta{ + Name: "acid-fake-cluster", + Namespace: namespace, + }, + Spec: acidv1.PostgresSpec{ + Volume: acidv1.Volume{ + Size: "1Gi", + }, + }, + } + + var cluster = New( + Config{ + OpConfig: config.Config{ + ConnectionPooler: config.ConnectionPooler{ + ConnectionPoolerDefaultCPURequest: "100m", + ConnectionPoolerDefaultCPULimit: "100m", + ConnectionPoolerDefaultMemoryRequest: "100Mi", + ConnectionPoolerDefaultMemoryLimit: "100Mi", + NumberOfInstances: int32ToPointer(1), + }, + PodManagementPolicy: "ordered_ready", + Resources: config.Resources{ + ClusterLabels: map[string]string{"application": "spilo"}, + ClusterNameLabel: "cluster-name", + DefaultCPURequest: "300m", + DefaultCPULimit: "300m", + DefaultMemoryRequest: "300Mi", + DefaultMemoryLimit: "300Mi", + PodRoleLabel: "spilo-role", + }, + }, + }, client, pg, logger, eventRecorder) + + cluster.Name = "acid-fake-cluster" + cluster.Namespace = "default" + + _, err := cluster.createService(Master) + assert.NoError(t, err) + _, err = cluster.createStatefulSet() + assert.NoError(t, err) + + reason, err := cluster.createConnectionPooler(mockInstallLookupFunction) + + if err != nil { + t.Errorf("%s: Cannot create connection pooler, %s, %+v", + testName, err, reason) } tests := []struct { @@ -358,10 +450,10 @@ func TestConnectionPoolerSynchronization(t *testing.T) { ConnectionPooler: &acidv1.ConnectionPooler{}, }, }, - cluster: newCluster(k8sutil.ClientMissingObjects()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, - check: MasterobjectsAreSaved, + check: MasterObjectsAreSaved, }, { subTest: "create if doesn't exist", @@ -375,10 +467,10 @@ func TestConnectionPoolerSynchronization(t *testing.T) { ConnectionPooler: &acidv1.ConnectionPooler{}, }, }, - cluster: newCluster(k8sutil.ClientMissingObjects()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, - check: MasterobjectsAreSaved, + check: MasterObjectsAreSaved, }, { subTest: "create if doesn't exist with a flag", @@ -390,10 +482,10 @@ func TestConnectionPoolerSynchronization(t *testing.T) { EnableConnectionPooler: boolToPointer(true), }, }, - cluster: newCluster(k8sutil.ClientMissingObjects()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, - check: MasterobjectsAreSaved, + check: MasterObjectsAreSaved, }, { subTest: "create no replica with flag", @@ -405,7 +497,7 @@ func TestConnectionPoolerSynchronization(t *testing.T) { EnableReplicaConnectionPooler: boolToPointer(false), }, }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, check: objectsAreDeleted, @@ -421,10 +513,10 @@ func TestConnectionPoolerSynchronization(t *testing.T) { EnableReplicaConnectionPooler: boolToPointer(true), }, }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, - check: ReplicaobjectsAreSaved, + check: ReplicaObjectsAreSaved, }, { subTest: "create both master and replica", @@ -438,7 +530,7 @@ func TestConnectionPoolerSynchronization(t *testing.T) { EnableConnectionPooler: boolToPointer(true), }, }, - cluster: newCluster(k8sutil.ClientMissingObjects()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, check: objectsAreSaved, @@ -456,7 +548,7 @@ func TestConnectionPoolerSynchronization(t *testing.T) { ConnectionPooler: &acidv1.ConnectionPooler{}, }, }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, check: OnlyReplicaDeleted, @@ -474,7 +566,7 @@ func TestConnectionPoolerSynchronization(t *testing.T) { EnableReplicaConnectionPooler: boolToPointer(true), }, }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, check: OnlyMasterDeleted, @@ -489,7 +581,7 @@ func TestConnectionPoolerSynchronization(t *testing.T) { newSpec: &acidv1.Postgresql{ Spec: acidv1.PostgresSpec{}, }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, check: objectsAreDeleted, @@ -502,53 +594,11 @@ func TestConnectionPoolerSynchronization(t *testing.T) { newSpec: &acidv1.Postgresql{ Spec: acidv1.PostgresSpec{}, }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, check: objectsAreDeleted, }, - { - subTest: "update deployment", - oldSpec: &acidv1.Postgresql{ - Spec: acidv1.PostgresSpec{ - ConnectionPooler: &acidv1.ConnectionPooler{ - NumberOfInstances: int32ToPointer(1), - }, - }, - }, - newSpec: &acidv1.Postgresql{ - Spec: acidv1.PostgresSpec{ - ConnectionPooler: &acidv1.ConnectionPooler{ - NumberOfInstances: int32ToPointer(2), - }, - }, - }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), - defaultImage: "pooler:1.0", - defaultInstances: 1, - check: deploymentUpdated, - }, - { - subTest: "update deployment", - oldSpec: &acidv1.Postgresql{ - Spec: acidv1.PostgresSpec{ - ConnectionPooler: &acidv1.ConnectionPooler{ - NumberOfInstances: int32ToPointer(1), - }, - }, - }, - newSpec: &acidv1.Postgresql{ - Spec: acidv1.PostgresSpec{ - ConnectionPooler: &acidv1.ConnectionPooler{ - NumberOfInstances: int32ToPointer(2), - }, - }, - }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), - defaultImage: "pooler:1.0", - defaultInstances: 1, - check: deploymentUpdated, - }, { subTest: "update image from changed defaults", oldSpec: &acidv1.Postgresql{ @@ -561,7 +611,7 @@ func TestConnectionPoolerSynchronization(t *testing.T) { ConnectionPooler: &acidv1.ConnectionPooler{}, }, }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), + cluster: cluster, defaultImage: "pooler:2.0", defaultInstances: 2, check: deploymentUpdated, @@ -580,7 +630,7 @@ func TestConnectionPoolerSynchronization(t *testing.T) { ConnectionPooler: &acidv1.ConnectionPooler{}, }, }, - cluster: newCluster(k8sutil.NewMockKubernetesClient()), + cluster: cluster, defaultImage: "pooler:1.0", defaultInstances: 1, check: noEmptySync, @@ -591,6 +641,8 @@ func TestConnectionPoolerSynchronization(t *testing.T) { tt.cluster.OpConfig.ConnectionPooler.NumberOfInstances = int32ToPointer(tt.defaultInstances) + t.Logf("running test for %s [%s]", testName, tt.subTest) + reason, err := tt.cluster.syncConnectionPooler(tt.oldSpec, tt.newSpec, mockInstallLookupFunction) From 4ea0b5f432e3d1ff084d2904a81f12ad84d709dc Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Fri, 22 Jan 2021 14:06:19 +0100 Subject: [PATCH 07/26] set AllowPrivilegeEscalation on container securityContext (#1326) --- .../templates/clusterrole-postgres-pod.yaml | 2 ++ .../templates/clusterrole.yaml | 4 ++- manifests/operator-service-account-rbac.yaml | 36 +++++++++---------- pkg/cluster/k8sres.go | 5 +-- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/charts/postgres-operator/templates/clusterrole-postgres-pod.yaml b/charts/postgres-operator/templates/clusterrole-postgres-pod.yaml index b3f9f08f5..33c43822f 100644 --- a/charts/postgres-operator/templates/clusterrole-postgres-pod.yaml +++ b/charts/postgres-operator/templates/clusterrole-postgres-pod.yaml @@ -63,6 +63,7 @@ rules: - services verbs: - create +{{- if toString .Values.configKubernetes.spilo_privileged | eq "true" }} # to run privileged pods - apiGroups: - extensions @@ -72,4 +73,5 @@ rules: - privileged verbs: - use +{{- end }} {{ end }} diff --git a/charts/postgres-operator/templates/clusterrole.yaml b/charts/postgres-operator/templates/clusterrole.yaml index 165cce7c6..885bad3f7 100644 --- a/charts/postgres-operator/templates/clusterrole.yaml +++ b/charts/postgres-operator/templates/clusterrole.yaml @@ -228,7 +228,8 @@ rules: verbs: - get - create -# to grant privilege to run privileged pods +{{- if toString .Values.configKubernetes.spilo_privileged | eq "true" }} +# to run privileged pods - apiGroups: - extensions resources: @@ -237,4 +238,5 @@ rules: - privileged verbs: - use +{{- end }} {{ end }} diff --git a/manifests/operator-service-account-rbac.yaml b/manifests/operator-service-account-rbac.yaml index 1ba5b4d23..f0307f6a0 100644 --- a/manifests/operator-service-account-rbac.yaml +++ b/manifests/operator-service-account-rbac.yaml @@ -203,15 +203,15 @@ rules: verbs: - get - create -# to grant privilege to run privileged pods -- apiGroups: - - extensions - resources: - - podsecuritypolicies - resourceNames: - - privileged - verbs: - - use +# to grant privilege to run privileged pods (not needed by default) +#- apiGroups: +# - extensions +# resources: +# - podsecuritypolicies +# resourceNames: +# - privileged +# verbs: +# - use --- apiVersion: rbac.authorization.k8s.io/v1 @@ -265,12 +265,12 @@ rules: - services verbs: - create -# to run privileged pods -- apiGroups: - - extensions - resources: - - podsecuritypolicies - resourceNames: - - privileged - verbs: - - use +# to grant privilege to run privileged pods (not needed by default) +#- apiGroups: +# - extensions +# resources: +# - podsecuritypolicies +# resourceNames: +# - privileged +# verbs: +# - use diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 06b074b4c..83098b8a9 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -453,8 +453,9 @@ func generateContainer( VolumeMounts: volumeMounts, Env: envVars, SecurityContext: &v1.SecurityContext{ - Privileged: &privilegedMode, - ReadOnlyRootFilesystem: util.False(), + AllowPrivilegeEscalation: &privilegedMode, + Privileged: &privilegedMode, + ReadOnlyRootFilesystem: util.False(), }, } } From 4a88f00a3f8e56fde9bd31b9a7cd704cd6b949cc Mon Sep 17 00:00:00 2001 From: Jan Mussler Date: Mon, 25 Jan 2021 10:07:18 +0100 Subject: [PATCH 08/26] Full AWS gp3 support for iops and througput config. (#1261) Support new AWS EBS volume type `gp3` with `iops` and `throughput` in the manifest. Co-authored-by: Felix Kunde --- .../postgres-operator/crds/postgresqls.yaml | 4 + docs/developer.md | 18 ++ docs/reference/cluster_manifest.md | 12 +- docs/reference/operator_parameters.md | 11 +- go.mod | 2 +- go.sum | 8 +- manifests/complete-postgres-manifest.yaml | 2 + manifests/postgresql.crd.yaml | 4 + pkg/apis/acid.zalan.do/v1/crds.go | 6 + pkg/apis/acid.zalan.do/v1/postgresql_type.go | 1 + pkg/cluster/sync.go | 72 +---- pkg/cluster/volumes.go | 240 ++++++++++++-- pkg/cluster/volumes_test.go | 305 +++++++++++++++--- pkg/util/volumes/ebs.go | 13 +- pkg/util/volumes/volumes.go | 2 +- 15 files changed, 535 insertions(+), 165 deletions(-) diff --git a/charts/postgres-operator/crds/postgresqls.yaml b/charts/postgres-operator/crds/postgresqls.yaml index 13811936d..ad11f6407 100644 --- a/charts/postgres-operator/crds/postgresqls.yaml +++ b/charts/postgres-operator/crds/postgresqls.yaml @@ -557,6 +557,8 @@ spec: required: - size properties: + iops: + type: integer size: type: string pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' @@ -565,6 +567,8 @@ spec: type: string subPath: type: string + throughput: + type: integer status: type: object additionalProperties: diff --git a/docs/developer.md b/docs/developer.md index 3316ac4cc..8ab1e60bc 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -235,6 +235,24 @@ Then you can for example check the Patroni logs: kubectl logs acid-minimal-cluster-0 ``` +## Unit tests with Mocks and K8s Fake API + +Whenever possible you should rely on leveraging proper mocks and K8s fake client that allows full fledged testing of K8s objects in your unit tests. + +To enable mocks, a code annotation is needed: +[Mock code gen annotation](https://github.com/zalando/postgres-operator/blob/master/pkg/util/volumes/volumes.go#L3) + +To generate mocks run: +```bash +make mocks +``` + +Examples for mocks can be found in: +[Example mock usage](https://github.com/zalando/postgres-operator/blob/master/pkg/cluster/volumes_test.go#L248) + +Examples for fake K8s objects can be found in: +[Example fake K8s client usage](https://github.com/zalando/postgres-operator/blob/master/pkg/cluster/volumes_test.go#L166) + ## End-to-end tests The operator provides reference end-to-end (e2e) tests to diff --git a/docs/reference/cluster_manifest.md b/docs/reference/cluster_manifest.md index 589921bc5..1b2d71a66 100644 --- a/docs/reference/cluster_manifest.md +++ b/docs/reference/cluster_manifest.md @@ -338,13 +338,13 @@ archive is supported. the url to S3 bucket containing the WAL archive of the remote primary. Required when the `standby` section is present. -## EBS volume resizing +## Volume properties Those parameters are grouped under the `volume` top-level key and define the properties of the persistent storage that stores Postgres data. * **size** - the size of the target EBS volume. Usual Kubernetes size modifiers, i.e. `Gi` + the size of the target volume. Usual Kubernetes size modifiers, i.e. `Gi` or `Mi`, apply. Required. * **storageClass** @@ -356,6 +356,14 @@ properties of the persistent storage that stores Postgres data. * **subPath** Subpath to use when mounting volume into Spilo container. Optional. +* **iops** + When running the operator on AWS the latest generation of EBS volumes (`gp3`) + allows for configuring the number of IOPS. Maximum is 16000. Optional. + +* **throughput** + When running the operator on AWS the latest generation of EBS volumes (`gp3`) + allows for configuring the throughput in MB/s. Maximum is 1000. Optional. + ## Sidecar definitions Those parameters are defined under the `sidecars` key. They consist of a list diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index 212515dc1..5c5850505 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -373,10 +373,13 @@ configuration they are grouped under the `kubernetes` key. possible value is `parallel`. * **storage_resize_mode** - defines how operator handels the difference between requested volume size and - actual size. Available options are: ebs - tries to resize EBS volume, pvc - - changes PVC definition, off - disables resize of the volumes. Default is "pvc". - When using OpenShift please use one of the other available options. + defines how operator handles the difference between the requested volume size and + the actual size. Available options are: + 1. `ebs` : operator resizes EBS volumes directly and executes `resizefs` within a pod + 2. `pvc` : operator only changes PVC definition + 3. `off` : disables resize of the volumes. + 4. `mixed` :operator uses AWS API to adjust size, throughput, and IOPS, and calls pvc change for file system resize + Default is "pvc". ## Kubernetes resource requests diff --git a/go.mod b/go.mod index 4e9c8a742..bbe5140b7 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/zalando/postgres-operator go 1.15 require ( - github.com/aws/aws-sdk-go v1.36.3 + github.com/aws/aws-sdk-go v1.36.29 github.com/golang/mock v1.4.4 github.com/lib/pq v1.9.0 github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d diff --git a/go.sum b/go.sum index d8df3fda4..fa8d2b135 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ 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/Storytel/gomock-matchers v1.2.0 h1:VPsbL6c/9/eCa4rH13LOEXPsIsnA1z+INamGIx1lWQo= +github.com/Storytel/gomock-matchers v1.2.0/go.mod h1:7HEuwyU/eq/W3mrSqPSYETGXiTyU2um0Rrb+dh5KmKM= 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/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -45,8 +47,8 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.36.3 h1:KYpG5OegwW3xgOsMxy01nj/Td281yxi1Ha2lJQJs4tI= -github.com/aws/aws-sdk-go v1.36.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.36.29 h1:lM1G3AF1+7vzFm0n7hfH8r2+750BTo+6Lo6FtPB7kzk= +github.com/aws/aws-sdk-go v1.36.29/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -182,6 +184,7 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/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= +github.com/golang/mock v1.2.1-0.20190311213431-837231f7bb37/go.mod h1:L3bP22mxdfCUHSUVMs+SPJMx55FrxQew7MSXT11Q86g= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= @@ -525,6 +528,7 @@ golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGm 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-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 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= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index 412bac29b..f721f0ccb 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -44,6 +44,8 @@ spec: volume: size: 1Gi # storageClass: my-sc +# iops: 1000 # for EBS gp3 + # throughput: 250 # in MB/s for EBS gp3 additionalVolumes: - name: empty mountPath: /opt/empty diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index d5170e9d4..61a04144c 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -553,6 +553,8 @@ spec: required: - size properties: + iops: + type: integer size: type: string pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' @@ -561,6 +563,8 @@ spec: type: string subPath: type: string + throughput: + type: integer status: type: object additionalProperties: diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index f03b4c2ab..02d40342f 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -835,6 +835,9 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ Type: "object", Required: []string{"size"}, Properties: map[string]apiextv1.JSONSchemaProps{ + "iops": { + Type: "integer", + }, "size": { Type: "string", Description: "Value must not be zero", @@ -846,6 +849,9 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ "subPath": { Type: "string", }, + "throughput": { + Type: "integer", + }, }, }, }, diff --git a/pkg/apis/acid.zalan.do/v1/postgresql_type.go b/pkg/apis/acid.zalan.do/v1/postgresql_type.go index bdae22a7c..7346fb0e5 100644 --- a/pkg/apis/acid.zalan.do/v1/postgresql_type.go +++ b/pkg/apis/acid.zalan.do/v1/postgresql_type.go @@ -118,6 +118,7 @@ type Volume struct { SubPath string `json:"subPath,omitempty"` Iops *int64 `json:"iops,omitempty"` Throughput *int64 `json:"throughput,omitempty"` + VolumeType string `json:"type,omitempty"` } // AdditionalVolume specs additional optional volumes for statefulset diff --git a/pkg/cluster/sync.go b/pkg/cluster/sync.go index dc54ae8ee..5c0f6ce84 100644 --- a/pkg/cluster/sync.go +++ b/pkg/cluster/sync.go @@ -53,8 +53,6 @@ func (c *Cluster) Sync(newSpec *acidv1.Postgresql) error { return err } - c.logger.Debugf("syncing volumes using %q storage resize mode", c.OpConfig.StorageResizeMode) - if c.OpConfig.EnableEBSGp3Migration { err = c.executeEBSMigration() if nil != err { @@ -62,32 +60,8 @@ func (c *Cluster) Sync(newSpec *acidv1.Postgresql) error { } } - if c.OpConfig.StorageResizeMode == "mixed" { - // mixed op uses AWS API to adjust size,throughput,iops and calls pvc chance for file system resize - - // resize pvc to adjust filesystem size until better K8s support - if err = c.syncVolumeClaims(); err != nil { - err = fmt.Errorf("could not sync persistent volume claims: %v", err) - return err - } - } else if c.OpConfig.StorageResizeMode == "pvc" { - if err = c.syncVolumeClaims(); err != nil { - err = fmt.Errorf("could not sync persistent volume claims: %v", err) - return err - } - } else if c.OpConfig.StorageResizeMode == "ebs" { - // potentially enlarge volumes before changing the statefulset. By doing that - // in this order we make sure the operator is not stuck waiting for a pod that - // cannot start because it ran out of disk space. - // TODO: handle the case of the cluster that is downsized and enlarged again - // (there will be a volume from the old pod for which we can't act before the - // the statefulset modification is concluded) - if err = c.syncVolumes(); err != nil { - err = fmt.Errorf("could not sync persistent volumes: %v", err) - return err - } - } else { - c.logger.Infof("Storage resize is disabled (storage_resize_mode is off). Skipping volume sync.") + if err = c.syncVolumes(); err != nil { + return err } if err = c.enforceMinResourceLimits(&c.Spec); err != nil { @@ -590,48 +564,6 @@ func (c *Cluster) syncRoles() (err error) { return nil } -// syncVolumeClaims reads all persistent volume claims and checks that their size matches the one declared in the statefulset. -func (c *Cluster) syncVolumeClaims() error { - c.setProcessName("syncing volume claims") - - act, err := c.volumeClaimsNeedResizing(c.Spec.Volume) - if err != nil { - return fmt.Errorf("could not compare size of the volume claims: %v", err) - } - if !act { - c.logger.Infof("volume claims do not require changes") - return nil - } - if err := c.resizeVolumeClaims(c.Spec.Volume); err != nil { - return fmt.Errorf("could not sync volume claims: %v", err) - } - - c.logger.Infof("volume claims have been synced successfully") - - return nil -} - -// syncVolumes reads all persistent volumes and checks that their size matches the one declared in the statefulset. -func (c *Cluster) syncVolumes() error { - c.setProcessName("syncing volumes") - - act, err := c.volumesNeedResizing(c.Spec.Volume) - if err != nil { - return fmt.Errorf("could not compare size of the volumes: %v", err) - } - if !act { - return nil - } - - if err := c.resizeVolumes(); err != nil { - return fmt.Errorf("could not sync volumes: %v", err) - } - - c.logger.Infof("volumes have been synced successfully") - - return nil -} - func (c *Cluster) syncDatabases() error { c.setProcessName("syncing databases") diff --git a/pkg/cluster/volumes.go b/pkg/cluster/volumes.go index 162d24075..e07d453ec 100644 --- a/pkg/cluster/volumes.go +++ b/pkg/cluster/volumes.go @@ -10,13 +10,215 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/aws/aws-sdk-go/aws" acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" "github.com/zalando/postgres-operator/pkg/spec" "github.com/zalando/postgres-operator/pkg/util" "github.com/zalando/postgres-operator/pkg/util/constants" "github.com/zalando/postgres-operator/pkg/util/filesystems" + "github.com/zalando/postgres-operator/pkg/util/volumes" ) +func (c *Cluster) syncVolumes() error { + c.logger.Debugf("syncing volumes using %q storage resize mode", c.OpConfig.StorageResizeMode) + var err error + + // check quantity string once, and do not bother with it anymore anywhere else + _, err = resource.ParseQuantity(c.Spec.Volume.Size) + if err != nil { + return fmt.Errorf("could not parse volume size from the manifest: %v", err) + } + + if c.OpConfig.StorageResizeMode == "mixed" { + // mixed op uses AWS API to adjust size, throughput, iops, and calls pvc change for file system resize + // in case of errors we proceed to let K8s do its work, favoring disk space increase of other adjustments + + err = c.populateVolumeMetaData() + if err != nil { + c.logger.Errorf("populating EBS meta data failed, skipping potential adjustements: %v", err) + } else { + err = c.syncUnderlyingEBSVolume() + if err != nil { + c.logger.Errorf("errors occured during EBS volume adjustments: %v", err) + } + } + + // resize pvc to adjust filesystem size until better K8s support + if err = c.syncVolumeClaims(); err != nil { + err = fmt.Errorf("could not sync persistent volume claims: %v", err) + return err + } + } else if c.OpConfig.StorageResizeMode == "pvc" { + if err = c.syncVolumeClaims(); err != nil { + err = fmt.Errorf("could not sync persistent volume claims: %v", err) + return err + } + } else if c.OpConfig.StorageResizeMode == "ebs" { + // potentially enlarge volumes before changing the statefulset. By doing that + // in this order we make sure the operator is not stuck waiting for a pod that + // cannot start because it ran out of disk space. + // TODO: handle the case of the cluster that is downsized and enlarged again + // (there will be a volume from the old pod for which we can't act before the + // the statefulset modification is concluded) + if err = c.syncEbsVolumes(); err != nil { + err = fmt.Errorf("could not sync persistent volumes: %v", err) + return err + } + } else { + c.logger.Infof("Storage resize is disabled (storage_resize_mode is off). Skipping volume sync.") + } + + return nil +} + +func (c *Cluster) syncUnderlyingEBSVolume() error { + c.logger.Infof("starting to sync EBS volumes: type, iops, throughput, and size") + + var err error + + targetValue := c.Spec.Volume + newSize, err := resource.ParseQuantity(targetValue.Size) + targetSize := quantityToGigabyte(newSize) + + awsGp3 := aws.String("gp3") + awsIo2 := aws.String("io2") + + errors := []string{} + + for _, volume := range c.EBSVolumes { + var modifyIops *int64 + var modifyThroughput *int64 + var modifySize *int64 + var modifyType *string + + if targetValue.Iops != nil { + if volume.Iops != *targetValue.Iops { + modifyIops = targetValue.Iops + } + } + + if targetValue.Throughput != nil { + if volume.Throughput != *targetValue.Throughput { + modifyThroughput = targetValue.Throughput + } + } + + if targetSize > volume.Size { + modifySize = &targetSize + } + + if modifyIops != nil || modifyThroughput != nil || modifySize != nil { + if modifyIops != nil || modifyThroughput != nil { + // we default to gp3 if iops and throughput are configured + modifyType = awsGp3 + if targetValue.VolumeType == "io2" { + modifyType = awsIo2 + } + } else if targetValue.VolumeType == "gp3" && volume.VolumeType != "gp3" { + modifyType = awsGp3 + } else { + // do not touch type + modifyType = nil + } + + err = c.VolumeResizer.ModifyVolume(volume.VolumeID, modifyType, modifySize, modifyIops, modifyThroughput) + if err != nil { + errors = append(errors, fmt.Sprintf("modify volume failed: volume=%s size=%d iops=%d throughput=%d", volume.VolumeID, volume.Size, volume.Iops, volume.Throughput)) + } + } + } + + if len(errors) > 0 { + for _, s := range errors { + c.logger.Warningf(s) + } + // c.logger.Errorf("failed to modify %d of %d volumes", len(c.EBSVolumes), len(errors)) + } + return nil +} + +func (c *Cluster) populateVolumeMetaData() error { + c.logger.Infof("starting reading ebs meta data") + + pvs, err := c.listPersistentVolumes() + if err != nil { + return fmt.Errorf("could not list persistent volumes: %v", err) + } + c.logger.Debugf("found %d volumes, size of known volumes %d", len(pvs), len(c.EBSVolumes)) + + volumeIds := []string{} + var volumeID string + for _, pv := range pvs { + volumeID, err = c.VolumeResizer.ExtractVolumeID(pv.Spec.AWSElasticBlockStore.VolumeID) + if err != nil { + continue + } + + volumeIds = append(volumeIds, volumeID) + } + + currentVolumes, err := c.VolumeResizer.DescribeVolumes(volumeIds) + if nil != err { + return err + } + + if len(currentVolumes) != len(c.EBSVolumes) { + c.logger.Debugf("number of ebs volumes (%d) discovered differs from already known volumes (%d)", len(currentVolumes), len(c.EBSVolumes)) + } + + // reset map, operator is not responsible for dangling ebs volumes + c.EBSVolumes = make(map[string]volumes.VolumeProperties) + for _, volume := range currentVolumes { + c.EBSVolumes[volume.VolumeID] = volume + } + + return nil +} + +// syncVolumeClaims reads all persistent volume claims and checks that their size matches the one declared in the statefulset. +func (c *Cluster) syncVolumeClaims() error { + c.setProcessName("syncing volume claims") + + needsResizing, err := c.volumeClaimsNeedResizing(c.Spec.Volume) + if err != nil { + return fmt.Errorf("could not compare size of the volume claims: %v", err) + } + + if !needsResizing { + c.logger.Infof("volume claims do not require changes") + return nil + } + + if err := c.resizeVolumeClaims(c.Spec.Volume); err != nil { + return fmt.Errorf("could not sync volume claims: %v", err) + } + + c.logger.Infof("volume claims have been synced successfully") + + return nil +} + +// syncVolumes reads all persistent volumes and checks that their size matches the one declared in the statefulset. +func (c *Cluster) syncEbsVolumes() error { + c.setProcessName("syncing EBS and Claims volumes") + + act, err := c.volumesNeedResizing() + if err != nil { + return fmt.Errorf("could not compare size of the volumes: %v", err) + } + if !act { + return nil + } + + if err := c.resizeVolumes(); err != nil { + return fmt.Errorf("could not sync volumes: %v", err) + } + + c.logger.Infof("volumes have been synced successfully") + + return nil +} + func (c *Cluster) listPersistentVolumeClaims() ([]v1.PersistentVolumeClaim, error) { ns := c.Namespace listOptions := metav1.ListOptions{ @@ -125,15 +327,16 @@ func (c *Cluster) resizeVolumes() error { c.setProcessName("resizing EBS volumes") - resizer := c.VolumeResizer - var totalIncompatible int - newQuantity, err := resource.ParseQuantity(c.Spec.Volume.Size) if err != nil { return fmt.Errorf("could not parse volume size: %v", err) } - pvs, newSize, err := c.listVolumesWithManifestSize(c.Spec.Volume) + newSize := quantityToGigabyte(newQuantity) + resizer := c.VolumeResizer + var totalIncompatible int + + pvs, err := c.listPersistentVolumes() if err != nil { return fmt.Errorf("could not list persistent volumes: %v", err) } @@ -214,33 +417,23 @@ func (c *Cluster) volumeClaimsNeedResizing(newVolume acidv1.Volume) (bool, error return false, nil } -func (c *Cluster) volumesNeedResizing(newVolume acidv1.Volume) (bool, error) { - vols, manifestSize, err := c.listVolumesWithManifestSize(newVolume) +func (c *Cluster) volumesNeedResizing() (bool, error) { + newQuantity, _ := resource.ParseQuantity(c.Spec.Volume.Size) + newSize := quantityToGigabyte(newQuantity) + + vols, err := c.listPersistentVolumes() if err != nil { return false, err } for _, pv := range vols { currentSize := quantityToGigabyte(pv.Spec.Capacity[v1.ResourceStorage]) - if currentSize != manifestSize { + if currentSize != newSize { return true, nil } } return false, nil } -func (c *Cluster) listVolumesWithManifestSize(newVolume acidv1.Volume) ([]*v1.PersistentVolume, int64, error) { - newSize, err := resource.ParseQuantity(newVolume.Size) - if err != nil { - return nil, 0, fmt.Errorf("could not parse volume size from the manifest: %v", err) - } - manifestSize := quantityToGigabyte(newSize) - vols, err := c.listPersistentVolumes() - if err != nil { - return nil, 0, fmt.Errorf("could not list persistent volumes: %v", err) - } - return vols, manifestSize, nil -} - // getPodNameFromPersistentVolume returns a pod name that it extracts from the volume claim ref. func getPodNameFromPersistentVolume(pv *v1.PersistentVolume) *spec.NamespacedName { namespace := pv.Spec.ClaimRef.Namespace @@ -258,7 +451,7 @@ func (c *Cluster) executeEBSMigration() error { } c.logger.Infof("starting EBS gp2 to gp3 migration") - pvs, _, err := c.listVolumesWithManifestSize(c.Spec.Volume) + pvs, err := c.listPersistentVolumes() if err != nil { return fmt.Errorf("could not list persistent volumes: %v", err) } @@ -294,10 +487,13 @@ func (c *Cluster) executeEBSMigration() error { return err } + var i3000 int64 = 3000 + var i125 int64 = 125 + for _, volume := range awsVolumes { if volume.VolumeType == "gp2" && volume.Size < c.OpConfig.EnableEBSGp3MigrationMaxSize { c.logger.Infof("modifying EBS volume %s to type gp3 migration (%d)", volume.VolumeID, volume.Size) - err = c.VolumeResizer.ModifyVolume(volume.VolumeID, "gp3", volume.Size, 3000, 125) + err = c.VolumeResizer.ModifyVolume(volume.VolumeID, aws.String("gp3"), &volume.Size, &i3000, &i125) if nil != err { c.logger.Warningf("modifying volume %s failed: %v", volume.VolumeID, err) } diff --git a/pkg/cluster/volumes_test.go b/pkg/cluster/volumes_test.go index 17fb8a4af..aea7711af 100644 --- a/pkg/cluster/volumes_test.go +++ b/pkg/cluster/volumes_test.go @@ -11,7 +11,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "github.com/aws/aws-sdk-go/aws" "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" "github.com/zalando/postgres-operator/mocks" acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" @@ -187,60 +189,16 @@ func TestMigrateEBS(t *testing.T) { cluster.Namespace = namespace filterLabels := cluster.labelsSet(false) - pvcList := CreatePVCs(namespace, clusterName, filterLabels, 2, "1Gi") - - ps := v1.PersistentVolumeSpec{} - ps.AWSElasticBlockStore = &v1.AWSElasticBlockStoreVolumeSource{} - ps.AWSElasticBlockStore.VolumeID = "aws://eu-central-1b/ebs-volume-1" - - ps2 := v1.PersistentVolumeSpec{} - ps2.AWSElasticBlockStore = &v1.AWSElasticBlockStoreVolumeSource{} - ps2.AWSElasticBlockStore.VolumeID = "aws://eu-central-1b/ebs-volume-2" - - pvList := &v1.PersistentVolumeList{ - Items: []v1.PersistentVolume{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "persistent-volume-0", - }, - Spec: ps, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "persistent-volume-1", - }, - Spec: ps2, - }, + testVolumes := []testVolume{ + { + size: 100, + }, + { + size: 100, }, } - for _, pvc := range pvcList.Items { - cluster.KubeClient.PersistentVolumeClaims(namespace).Create(context.TODO(), &pvc, metav1.CreateOptions{}) - } - - for _, pv := range pvList.Items { - cluster.KubeClient.PersistentVolumes().Create(context.TODO(), &pv, metav1.CreateOptions{}) - } - - pod := v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: clusterName + "-0", - Labels: filterLabels, - }, - Spec: v1.PodSpec{}, - } - - cluster.KubeClient.Pods(namespace).Create(context.TODO(), &pod, metav1.CreateOptions{}) - - pod = v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: clusterName + "-1", - Labels: filterLabels, - }, - Spec: v1.PodSpec{}, - } - - cluster.KubeClient.Pods(namespace).Create(context.TODO(), &pod, metav1.CreateOptions{}) + initTestVolumesAndPods(cluster.KubeClient, namespace, clusterName, filterLabels, testVolumes) ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -256,8 +214,251 @@ func TestMigrateEBS(t *testing.T) { {VolumeID: "ebs-volume-2", VolumeType: "gp3", Size: 100}}, nil) // expect only gp2 volume to be modified - resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Eq("gp3"), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Eq(aws.String("gp3")), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) cluster.VolumeResizer = resizer cluster.executeEBSMigration() } + +type testVolume struct { + iops int64 + throughtput int64 + size int64 + volType string +} + +func initTestVolumesAndPods(client k8sutil.KubernetesClient, namespace, clustername string, labels labels.Set, volumes []testVolume) { + i := 0 + for _, v := range volumes { + storage1Gi, _ := resource.ParseQuantity(fmt.Sprintf("%d", v.size)) + + ps := v1.PersistentVolumeSpec{} + ps.AWSElasticBlockStore = &v1.AWSElasticBlockStoreVolumeSource{} + ps.AWSElasticBlockStore.VolumeID = fmt.Sprintf("aws://eu-central-1b/ebs-volume-%d", i+1) + + pv := v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("persistent-volume-%d", i), + }, + Spec: ps, + } + + client.PersistentVolumes().Create(context.TODO(), &pv, metav1.CreateOptions{}) + + pvc := v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s-%d", constants.DataVolumeName, clustername, i), + Namespace: namespace, + Labels: labels, + }, + Spec: v1.PersistentVolumeClaimSpec{ + Resources: v1.ResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceStorage: storage1Gi, + }, + }, + VolumeName: fmt.Sprintf("persistent-volume-%d", i), + }, + } + + client.PersistentVolumeClaims(namespace).Create(context.TODO(), &pvc, metav1.CreateOptions{}) + + pod := v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%d", clustername, i), + Labels: labels, + }, + Spec: v1.PodSpec{}, + } + + client.Pods(namespace).Create(context.TODO(), &pod, metav1.CreateOptions{}) + + i = i + 1 + } +} + +func TestMigrateGp3Support(t *testing.T) { + client, _ := newFakeK8sPVCclient() + clusterName := "acid-test-cluster" + namespace := "default" + + // new cluster with pvc storage resize mode and configured labels + var cluster = New( + Config{ + OpConfig: config.Config{ + Resources: config.Resources{ + ClusterLabels: map[string]string{"application": "spilo"}, + ClusterNameLabel: "cluster-name", + }, + StorageResizeMode: "mixed", + EnableEBSGp3Migration: false, + EnableEBSGp3MigrationMaxSize: 1000, + }, + }, client, acidv1.Postgresql{}, logger, eventRecorder) + + cluster.Spec.Volume.Size = "150Gi" + cluster.Spec.Volume.Iops = aws.Int64(6000) + cluster.Spec.Volume.Throughput = aws.Int64(275) + + // set metadata, so that labels will get correct values + cluster.Name = clusterName + cluster.Namespace = namespace + filterLabels := cluster.labelsSet(false) + + testVolumes := []testVolume{ + { + size: 100, + }, + { + size: 100, + }, + { + size: 100, + }, + } + + initTestVolumesAndPods(cluster.KubeClient, namespace, clusterName, filterLabels, testVolumes) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resizer := mocks.NewMockVolumeResizer(ctrl) + + resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-1")).Return("ebs-volume-1", nil) + resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil) + resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-3")).Return("ebs-volume-3", nil) + + resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2", "ebs-volume-3"})).Return( + []volumes.VolumeProperties{ + {VolumeID: "ebs-volume-1", VolumeType: "gp3", Size: 100, Iops: 3000}, + {VolumeID: "ebs-volume-2", VolumeType: "gp3", Size: 105, Iops: 4000}, + {VolumeID: "ebs-volume-3", VolumeType: "gp3", Size: 151, Iops: 6000, Throughput: 275}}, nil) + + // expect only gp2 volume to be modified + resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Eq(aws.String("gp3")), gomock.Eq(aws.Int64(150)), gomock.Eq(aws.Int64(6000)), gomock.Eq(aws.Int64(275))).Return(nil) + resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-2"), gomock.Eq(aws.String("gp3")), gomock.Eq(aws.Int64(150)), gomock.Eq(aws.Int64(6000)), gomock.Eq(aws.Int64(275))).Return(nil) + // resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-3"), gomock.Eq(aws.String("gp3")), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + + cluster.VolumeResizer = resizer + cluster.syncVolumes() +} + +func TestManualGp2Gp3Support(t *testing.T) { + client, _ := newFakeK8sPVCclient() + clusterName := "acid-test-cluster" + namespace := "default" + + // new cluster with pvc storage resize mode and configured labels + var cluster = New( + Config{ + OpConfig: config.Config{ + Resources: config.Resources{ + ClusterLabels: map[string]string{"application": "spilo"}, + ClusterNameLabel: "cluster-name", + }, + StorageResizeMode: "mixed", + EnableEBSGp3Migration: false, + EnableEBSGp3MigrationMaxSize: 1000, + }, + }, client, acidv1.Postgresql{}, logger, eventRecorder) + + cluster.Spec.Volume.Size = "150Gi" + cluster.Spec.Volume.Iops = aws.Int64(6000) + cluster.Spec.Volume.Throughput = aws.Int64(275) + + // set metadata, so that labels will get correct values + cluster.Name = clusterName + cluster.Namespace = namespace + filterLabels := cluster.labelsSet(false) + + testVolumes := []testVolume{ + { + size: 100, + }, + { + size: 100, + }, + } + + initTestVolumesAndPods(cluster.KubeClient, namespace, clusterName, filterLabels, testVolumes) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resizer := mocks.NewMockVolumeResizer(ctrl) + + resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-1")).Return("ebs-volume-1", nil) + resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil) + + resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2"})).Return( + []volumes.VolumeProperties{ + {VolumeID: "ebs-volume-1", VolumeType: "gp2", Size: 150, Iops: 3000}, + {VolumeID: "ebs-volume-2", VolumeType: "gp2", Size: 150, Iops: 4000}, + }, nil) + + // expect only gp2 volume to be modified + resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Eq(aws.String("gp3")), gomock.Nil(), gomock.Eq(aws.Int64(6000)), gomock.Eq(aws.Int64(275))).Return(nil) + resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-2"), gomock.Eq(aws.String("gp3")), gomock.Nil(), gomock.Eq(aws.Int64(6000)), gomock.Eq(aws.Int64(275))).Return(nil) + + cluster.VolumeResizer = resizer + cluster.syncVolumes() +} + +func TestDontTouchType(t *testing.T) { + client, _ := newFakeK8sPVCclient() + clusterName := "acid-test-cluster" + namespace := "default" + + // new cluster with pvc storage resize mode and configured labels + var cluster = New( + Config{ + OpConfig: config.Config{ + Resources: config.Resources{ + ClusterLabels: map[string]string{"application": "spilo"}, + ClusterNameLabel: "cluster-name", + }, + StorageResizeMode: "mixed", + EnableEBSGp3Migration: false, + EnableEBSGp3MigrationMaxSize: 1000, + }, + }, client, acidv1.Postgresql{}, logger, eventRecorder) + + cluster.Spec.Volume.Size = "177Gi" + + // set metadata, so that labels will get correct values + cluster.Name = clusterName + cluster.Namespace = namespace + filterLabels := cluster.labelsSet(false) + + testVolumes := []testVolume{ + { + size: 150, + }, + { + size: 150, + }, + } + + initTestVolumesAndPods(cluster.KubeClient, namespace, clusterName, filterLabels, testVolumes) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + resizer := mocks.NewMockVolumeResizer(ctrl) + + resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-1")).Return("ebs-volume-1", nil) + resizer.EXPECT().ExtractVolumeID(gomock.Eq("aws://eu-central-1b/ebs-volume-2")).Return("ebs-volume-2", nil) + + resizer.EXPECT().DescribeVolumes(gomock.Eq([]string{"ebs-volume-1", "ebs-volume-2"})).Return( + []volumes.VolumeProperties{ + {VolumeID: "ebs-volume-1", VolumeType: "gp2", Size: 150, Iops: 3000}, + {VolumeID: "ebs-volume-2", VolumeType: "gp2", Size: 150, Iops: 4000}, + }, nil) + + // expect only gp2 volume to be modified + resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-1"), gomock.Nil(), gomock.Eq(aws.Int64(177)), gomock.Nil(), gomock.Nil()).Return(nil) + resizer.EXPECT().ModifyVolume(gomock.Eq("ebs-volume-2"), gomock.Nil(), gomock.Eq(aws.Int64(177)), gomock.Nil(), gomock.Nil()).Return(nil) + + cluster.VolumeResizer = resizer + cluster.syncVolumes() +} diff --git a/pkg/util/volumes/ebs.go b/pkg/util/volumes/ebs.go index 17016fb09..8f998b4cb 100644 --- a/pkg/util/volumes/ebs.go +++ b/pkg/util/volumes/ebs.go @@ -141,18 +141,9 @@ func (r *EBSVolumeResizer) ResizeVolume(volumeID string, newSize int64) error { } // ModifyVolume Modify EBS volume -func (r *EBSVolumeResizer) ModifyVolume(volumeID string, newType string, newSize int64, iops int64, throughput int64) error { +func (r *EBSVolumeResizer) ModifyVolume(volumeID string, newType *string, newSize *int64, iops *int64, throughput *int64) error { /* first check if the volume is already of a requested size */ - volumeOutput, err := r.connection.DescribeVolumes(&ec2.DescribeVolumesInput{VolumeIds: []*string{&volumeID}}) - if err != nil { - return fmt.Errorf("could not get information about the volume: %v", err) - } - vol := volumeOutput.Volumes[0] - if *vol.VolumeId != volumeID { - return fmt.Errorf("describe volume %q returned information about a non-matching volume %q", volumeID, *vol.VolumeId) - } - - input := ec2.ModifyVolumeInput{Size: &newSize, VolumeId: &volumeID, VolumeType: &newType, Iops: &iops, Throughput: &throughput} + input := ec2.ModifyVolumeInput{Size: newSize, VolumeId: &volumeID, VolumeType: newType, Iops: iops, Throughput: throughput} output, err := r.connection.ModifyVolume(&input) if err != nil { return fmt.Errorf("could not modify persistent volume: %v", err) diff --git a/pkg/util/volumes/volumes.go b/pkg/util/volumes/volumes.go index 9b44c0d00..556729dc4 100644 --- a/pkg/util/volumes/volumes.go +++ b/pkg/util/volumes/volumes.go @@ -21,7 +21,7 @@ type VolumeResizer interface { GetProviderVolumeID(pv *v1.PersistentVolume) (string, error) ExtractVolumeID(volumeID string) (string, error) ResizeVolume(providerVolumeID string, newSize int64) error - ModifyVolume(providerVolumeID string, newType string, newSize int64, iops int64, throughput int64) error + ModifyVolume(providerVolumeID string, newType *string, newSize *int64, iops *int64, throughput *int64) error DisconnectFromProvider() error DescribeVolumes(providerVolumesID []string) ([]VolumeProperties, error) } From 5ecb7b42e0f84c0fcbf48ae1b6d5c32af49061ec Mon Sep 17 00:00:00 2001 From: Sergey Dudoladov Date: Mon, 25 Jan 2021 17:00:14 +0100 Subject: [PATCH 09/26] persist modified go.sum (#1329) Co-authored-by: Sergey Dudoladov --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index fa8d2b135..64434e2e0 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,6 @@ 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/Storytel/gomock-matchers v1.2.0 h1:VPsbL6c/9/eCa4rH13LOEXPsIsnA1z+INamGIx1lWQo= -github.com/Storytel/gomock-matchers v1.2.0/go.mod h1:7HEuwyU/eq/W3mrSqPSYETGXiTyU2um0Rrb+dh5KmKM= 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/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -184,7 +182,6 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/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= -github.com/golang/mock v1.2.1-0.20190311213431-837231f7bb37/go.mod h1:L3bP22mxdfCUHSUVMs+SPJMx55FrxQew7MSXT11Q86g= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= @@ -528,7 +525,6 @@ golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGm 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-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 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= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= From ac2a00c45eadf1d99775b2ed77ebdf36f104116a Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Mon, 25 Jan 2021 18:23:29 +0100 Subject: [PATCH 10/26] set allowPrivilegeEscalation for deployment templates (#1328) * set allowPrivilegeEscalation for deployment templates * securityContext of container, not pod * aligning * default service account for pooler --- charts/postgres-operator/templates/deployment.yaml | 2 ++ charts/postgres-operator/values-crd.yaml | 14 ++++++++++---- charts/postgres-operator/values.yaml | 14 ++++++++++---- manifests/complete-postgres-manifest.yaml | 2 +- manifests/postgres-operator.yaml | 1 + pkg/cluster/connection_pooler.go | 4 +++- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/charts/postgres-operator/templates/deployment.yaml b/charts/postgres-operator/templates/deployment.yaml index 9841bf1bc..89500ae94 100644 --- a/charts/postgres-operator/templates/deployment.yaml +++ b/charts/postgres-operator/templates/deployment.yaml @@ -54,6 +54,8 @@ spec: {{- end }} resources: {{ toYaml .Values.resources | indent 10 }} + securityContext: +{{ toYaml .Values.securityContext | indent 10 }} {{- if .Values.imagePullSecrets }} imagePullSecrets: {{ toYaml .Values.imagePullSecrets | indent 8 }} diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index 3593dd276..f3115dc8e 100644 --- a/charts/postgres-operator/values-crd.yaml +++ b/charts/postgres-operator/values-crd.yaml @@ -359,18 +359,24 @@ resources: cpu: 100m memory: 250Mi +securityContext: + runAsUser: 1000 + runAsNonRoot: true + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + # Affinity for pod assignment # Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity affinity: {} -# Tolerations for pod assignment -# Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -tolerations: [] - # Node labels for pod assignment # Ref: https://kubernetes.io/docs/user-guide/node-selection/ nodeSelector: {} +# Tolerations for pod assignment +# Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +tolerations: [] + controllerID: # Specifies whether a controller ID should be defined for the operator # Note, all postgres manifest must then contain the following annotation to be found by this operator diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index 15f13df7e..e8a330d4b 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -354,18 +354,24 @@ resources: cpu: 100m memory: 250Mi +securityContext: + runAsUser: 1000 + runAsNonRoot: true + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + # Affinity for pod assignment # Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity affinity: {} -# Tolerations for pod assignment -# Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -tolerations: [] - # Node labels for pod assignment # Ref: https://kubernetes.io/docs/user-guide/node-selection/ nodeSelector: {} +# Tolerations for pod assignment +# Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +tolerations: [] + controllerID: # Specifies whether a controller ID should be defined for the operator # Note, all postgres manifest must then contain the following annotation to be found by this operator diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index f721f0ccb..9f2d19639 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -45,7 +45,7 @@ spec: size: 1Gi # storageClass: my-sc # iops: 1000 # for EBS gp3 - # throughput: 250 # in MB/s for EBS gp3 +# throughput: 250 # in MB/s for EBS gp3 additionalVolumes: - name: empty mountPath: /opt/empty diff --git a/manifests/postgres-operator.yaml b/manifests/postgres-operator.yaml index da4ca7fc6..a03959805 100644 --- a/manifests/postgres-operator.yaml +++ b/manifests/postgres-operator.yaml @@ -32,6 +32,7 @@ spec: runAsUser: 1000 runAsNonRoot: true readOnlyRootFilesystem: true + allowPrivilegeEscalation: false env: # provided additional ENV vars can overwrite individual config map entries - name: CONFIG_MAP_NAME diff --git a/pkg/cluster/connection_pooler.go b/pkg/cluster/connection_pooler.go index 2e3f04876..db4f1f56d 100644 --- a/pkg/cluster/connection_pooler.go +++ b/pkg/cluster/connection_pooler.go @@ -280,6 +280,9 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) ( }, }, }, + SecurityContext: &v1.SecurityContext{ + AllowPrivilegeEscalation: util.False(), + }, } podTemplate := &v1.PodTemplateSpec{ @@ -289,7 +292,6 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) ( Annotations: c.annotationsSet(c.generatePodAnnotations(spec)), }, Spec: v1.PodSpec{ - ServiceAccountName: c.OpConfig.PodServiceAccountName, TerminationGracePeriodSeconds: &gracePeriod, Containers: []v1.Container{poolerContainer}, // TODO: add tolerations to scheduler pooler on the same node From 43168ca62201d81a2c5d57b5b107b5481c0af0f7 Mon Sep 17 00:00:00 2001 From: Jan Mussler Date: Mon, 25 Jan 2021 20:28:37 +0100 Subject: [PATCH 11/26] Also sync volumes on updates. (#1330) --- pkg/cluster/cluster.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 42515a7c0..16d399865 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -659,20 +659,8 @@ func (c *Cluster) Update(oldSpec, newSpec *acidv1.Postgresql) error { } // Volume - if oldSpec.Spec.Size != newSpec.Spec.Size { - c.logVolumeChanges(oldSpec.Spec.Volume, newSpec.Spec.Volume) - c.logger.Debugf("syncing volumes using %q storage resize mode", c.OpConfig.StorageResizeMode) - if c.OpConfig.StorageResizeMode == "pvc" { - if err := c.syncVolumeClaims(); err != nil { - c.logger.Errorf("could not sync persistent volume claims: %v", err) - updateFailed = true - } - } else if c.OpConfig.StorageResizeMode == "ebs" { - if err := c.syncVolumes(); err != nil { - c.logger.Errorf("could not sync persistent volumes: %v", err) - updateFailed = true - } - } + if c.OpConfig.StorageResizeMode != "off" { + c.syncVolumes() } else { c.logger.Infof("Storage resize is disabled (storage_resize_mode is off). Skipping volume sync.") } From 9d5841cdaaefba9aba1a12112ebca9b7dee00eb4 Mon Sep 17 00:00:00 2001 From: Victor Login Date: Wed, 27 Jan 2021 12:11:44 +0300 Subject: [PATCH 12/26] Update values.yaml (#1333) --- charts/postgres-operator-ui/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/postgres-operator-ui/values.yaml b/charts/postgres-operator-ui/values.yaml index dea5007c9..2aef84f1c 100644 --- a/charts/postgres-operator-ui/values.yaml +++ b/charts/postgres-operator-ui/values.yaml @@ -52,7 +52,7 @@ service: port: "80" # If the type of the service is NodePort a port can be specified using the nodePort field # If the nodePort field is not specified, or if it has no value, then a random port is used - # notePort: 32521 + # nodePort: 32521 # configure UI ingress. If needed: "enabled: true" ingress: From d488ae10a04995a533d13c33a2e6da7106fa70b8 Mon Sep 17 00:00:00 2001 From: Jan Mussler Date: Fri, 29 Jan 2021 11:12:08 +0100 Subject: [PATCH 13/26] Min 2 zalando approvers. (#1338) --- .zappr.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.zappr.yaml b/.zappr.yaml index 999c121d7..00be0052e 100644 --- a/.zappr.yaml +++ b/.zappr.yaml @@ -3,3 +3,11 @@ X-Zalando-Team: "acid" # type should be one of [code, doc, config, tools, secrets] # code will be the default value, if X-Zalando-Type is not found in .zappr.yml X-Zalando-Type: code + +approvals: + groups: + zalando: + minimum: 2 + from: + orgs: + - zalando \ No newline at end of file From 12ad8c91fa0fcd1f82984b0da33b5e4f4d8c0ba3 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Fri, 29 Jan 2021 14:54:48 +0100 Subject: [PATCH 14/26] configurable container capabilities (#1336) * configurable container capabilities * revert change on TestTLS * fix e2e test * minor fix --- .../crds/operatorconfigurations.yaml | 4 ++ charts/postgres-operator/values-crd.yaml | 4 ++ charts/postgres-operator/values.yaml | 3 + docs/reference/operator_parameters.md | 6 ++ e2e/tests/k8s_api.py | 8 +++ e2e/tests/test_e2e.py | 19 ++++++ manifests/configmap.yaml | 1 + manifests/operatorconfiguration.crd.yaml | 4 ++ ...gresql-operator-default-configuration.yaml | 2 + pkg/apis/acid.zalan.do/v1/crds.go | 8 +++ .../v1/operator_configuration_type.go | 1 + .../acid.zalan.do/v1/zz_generated.deepcopy.go | 5 ++ pkg/cluster/k8sres.go | 17 +++++ pkg/cluster/k8sres_test.go | 39 +++++++++++ pkg/controller/operator_config.go | 1 + pkg/util/config/config.go | 65 ++++++++++--------- 16 files changed, 155 insertions(+), 32 deletions(-) diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index a360da0c6..ef9b2c84d 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -130,6 +130,10 @@ spec: kubernetes: type: object properties: + additional_pod_capabilities: + type: array + items: + type: string cluster_domain: type: string default: "cluster.local" diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index f3115dc8e..42af903cd 100644 --- a/charts/postgres-operator/values-crd.yaml +++ b/charts/postgres-operator/values-crd.yaml @@ -59,6 +59,10 @@ configUsers: super_username: postgres configKubernetes: + # list of additional capabilities for postgres container + # additional_pod_capabilities: + # - "SYS_NICE" + # default DNS domain of K8s cluster where operator is running cluster_domain: cluster.local # additional labels assigned to the cluster objects diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index e8a330d4b..c46e21e1f 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -61,6 +61,9 @@ configUsers: super_username: postgres configKubernetes: + # list of additional capabilities for postgres container + # additional_pod_capabilities: "SYS_NICE" + # default DNS domain of K8s cluster where operator is running cluster_domain: cluster.local # additional labels assigned to the cluster objects diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index 5c5850505..54d13ffc2 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -351,6 +351,12 @@ configuration they are grouped under the `kubernetes` key. used for AWS volume resizing and not required if you don't need that capability. The default is `false`. +* **additional_pod_capabilities** + list of additional capabilities to be added to the postgres container's + SecurityContext (e.g. SYS_NICE etc.). Please, make sure first that the + PodSecruityPolicy allows the capabilities listed here. Otherwise, the + container will not start. The default is empty. + * **master_pod_move_timeout** The period of time to wait for the success of migration of master pods from an unschedulable node. The migration includes Patroni switchovers to diff --git a/e2e/tests/k8s_api.py b/e2e/tests/k8s_api.py index 95e1dc9ad..21e2a16e9 100644 --- a/e2e/tests/k8s_api.py +++ b/e2e/tests/k8s_api.py @@ -182,6 +182,10 @@ class K8s: pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items return len(list(filter(lambda x: x.status.phase == 'Running', pods))) + def count_pods_with_container_capabilities(self, capabilities, labels, namespace='default'): + pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items + return len(list(filter(lambda x: x.spec.containers[0].security_context.capabilities.add == capabilities, pods))) + def wait_for_pod_failover(self, failover_targets, labels, namespace='default'): pod_phase = 'Failing over' new_pod_node = '' @@ -433,6 +437,10 @@ class K8sBase: pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items return len(list(filter(lambda x: x.status.phase == 'Running', pods))) + def count_pods_with_container_capabilities(self, capabilities, labels, namespace='default'): + pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items + return len(list(filter(lambda x: x.spec.containers[0].security_context.capabilities.add == capabilities, pods))) + def wait_for_pod_failover(self, failover_targets, labels, namespace='default'): pod_phase = 'Failing over' new_pod_node = '' diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index ecc0b2327..87bed3baa 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -155,6 +155,25 @@ class EndToEndTestCase(unittest.TestCase): print('Operator log: {}'.format(k8s.get_operator_log())) raise + @timeout_decorator.timeout(TEST_TIMEOUT_SEC) + def test_additional_pod_capabilities(self): + ''' + Extend postgres container capabilities + ''' + cluster_label = 'application=spilo,cluster-name=acid-minimal-cluster' + capabilities = ["SYS_NICE","CHOWN"] + patch_capabilities = { + "data": { + "additional_pod_capabilities": ','.join(capabilities), + }, + } + self.k8s.update_config(patch_capabilities) + self.eventuallyEqual(lambda: self.k8s.get_operator_state(), {"0": "idle"}, + "Operator does not get in sync") + + self.eventuallyEqual(lambda: self.k8s.count_pods_with_container_capabilities(capabilities, cluster_label), + 2, "Container capabilities not updated") + @timeout_decorator.timeout(TEST_TIMEOUT_SEC) def test_overwrite_pooler_deployment(self): self.k8s.create_with_kubectl("manifests/minimal-fake-pooler-deployment.yaml") diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 3788d8b32..f1bde6811 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -3,6 +3,7 @@ kind: ConfigMap metadata: name: postgres-operator data: + # additional_pod_capabilities: "SYS_NICE" # additional_secret_mount: "some-secret-name" # additional_secret_mount_path: "/some/dir" api_port: "8080" diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index 7add1b8c6..7388a765b 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -126,6 +126,10 @@ spec: kubernetes: type: object properties: + additional_pod_capabilities: + type: array + items: + type: string cluster_domain: type: string default: "cluster.local" diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index 96394976d..18680fbb0 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -26,6 +26,8 @@ configuration: replication_username: standby super_username: postgres kubernetes: + # additional_pod_capabilities: + # - "SYS_NICE" cluster_domain: cluster.local cluster_labels: application: spilo diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index 02d40342f..3c4bc315a 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -968,6 +968,14 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{ "kubernetes": { Type: "object", Properties: map[string]apiextv1.JSONSchemaProps{ + "additional_pod_capabilities": { + Type: "array", + Items: &apiextv1.JSONSchemaPropsOrArray{ + Schema: &apiextv1.JSONSchemaProps{ + Type: "string", + }, + }, + }, "cluster_domain": { 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 b55bfa492..cddaa9dd4 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -52,6 +52,7 @@ type KubernetesMetaConfiguration struct { SpiloRunAsUser *int64 `json:"spilo_runasuser,omitempty"` SpiloRunAsGroup *int64 `json:"spilo_runasgroup,omitempty"` SpiloFSGroup *int64 `json:"spilo_fsgroup,omitempty"` + AdditionalPodCapabilities []string `json:"additional_pod_capabilities,omitempty"` WatchedNamespace string `json:"watched_namespace,omitempty"` PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"` EnablePodDisruptionBudget *bool `json:"enable_pod_disruption_budget,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 4bcbd2f5e..81f8a76b5 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -162,6 +162,11 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura *out = new(int64) **out = **in } + if in.AdditionalPodCapabilities != nil { + in, out := &in.AdditionalPodCapabilities, &out.AdditionalPodCapabilities + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.EnablePodDisruptionBudget != nil { in, out := &in.EnablePodDisruptionBudget, &out.EnablePodDisruptionBudget *out = new(bool) diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 83098b8a9..56500bb29 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -320,6 +320,19 @@ func getLocalAndBoostrapPostgreSQLParameters(parameters map[string]string) (loca return } +func generateCapabilities(capabilities []string) v1.Capabilities { + if len(capabilities) > 1 { + additionalCapabilities := []v1.Capability{} + for _, capability := range capabilities { + additionalCapabilities = append(additionalCapabilities, v1.Capability(strings.ToUpper(capability))) + } + return v1.Capabilities{ + Add: additionalCapabilities, + } + } + return v1.Capabilities{} +} + func nodeAffinity(nodeReadinessLabel map[string]string, nodeAffinity *v1.NodeAffinity) *v1.Affinity { if len(nodeReadinessLabel) == 0 && nodeAffinity == nil { return nil @@ -430,6 +443,7 @@ func generateContainer( envVars []v1.EnvVar, volumeMounts []v1.VolumeMount, privilegedMode bool, + additionalPodCapabilities v1.Capabilities, ) *v1.Container { return &v1.Container{ Name: name, @@ -456,6 +470,7 @@ func generateContainer( AllowPrivilegeEscalation: &privilegedMode, Privileged: &privilegedMode, ReadOnlyRootFilesystem: util.False(), + Capabilities: &additionalPodCapabilities, }, } } @@ -1148,6 +1163,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef deduplicateEnvVars(spiloEnvVars, c.containerName(), c.logger), volumeMounts, c.OpConfig.Resources.SpiloPrivileged, + generateCapabilities(c.OpConfig.AdditionalPodCapabilities), ) // generate container specs for sidecars specified in the cluster manifest @@ -1901,6 +1917,7 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1beta1.CronJob, error) { envVars, []v1.VolumeMount{}, c.OpConfig.SpiloPrivileged, // use same value as for normal DB pods + v1.Capabilities{}, ) labels := map[string]string{ diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index e880fcc3b..6034db214 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -1489,3 +1489,42 @@ func TestGenerateService(t *testing.T) { assert.Equal(t, v1.ServiceExternalTrafficPolicyTypeLocal, service.Spec.ExternalTrafficPolicy) } + +func TestGenerateCapabilities(t *testing.T) { + + testName := "TestGenerateCapabilities" + tests := []struct { + subTest string + configured []string + capabilities v1.Capabilities + err error + }{ + { + subTest: "no capabilities", + configured: nil, + capabilities: v1.Capabilities{}, + err: fmt.Errorf("could not parse capabilities configuration of nil"), + }, + { + subTest: "empty capabilities", + configured: []string{}, + capabilities: v1.Capabilities{}, + err: fmt.Errorf("could not parse empty capabilities configuration"), + }, + { + subTest: "configured capabilities", + configured: []string{"SYS_NICE", "CHOWN"}, + capabilities: v1.Capabilities{ + Add: []v1.Capability{"SYS_NICE", "CHOWN"}, + }, + err: fmt.Errorf("could not parse empty capabilities configuration"), + }, + } + for _, tt := range tests { + caps := generateCapabilities(tt.configured) + if !reflect.DeepEqual(caps, tt.capabilities) { + t.Errorf("%s %s: expected `%v` but got `%v`", + testName, tt.subTest, tt.capabilities, caps) + } + } +} diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 16fb05004..6ef7a2f42 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -66,6 +66,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.SpiloRunAsUser = fromCRD.Kubernetes.SpiloRunAsUser result.SpiloRunAsGroup = fromCRD.Kubernetes.SpiloRunAsGroup result.SpiloFSGroup = fromCRD.Kubernetes.SpiloFSGroup + result.AdditionalPodCapabilities = fromCRD.Kubernetes.AdditionalPodCapabilities result.ClusterDomain = util.Coalesce(fromCRD.Kubernetes.ClusterDomain, "cluster.local") result.WatchedNamespace = fromCRD.Kubernetes.WatchedNamespace result.PDBNameFormat = fromCRD.Kubernetes.PDBNameFormat diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 1d8e37bd2..6bc5a6a28 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -23,38 +23,39 @@ type CRD struct { // Resources describes kubernetes resource specific configuration parameters type Resources struct { - ResourceCheckInterval time.Duration `name:"resource_check_interval" default:"3s"` - ResourceCheckTimeout time.Duration `name:"resource_check_timeout" default:"10m"` - PodLabelWaitTimeout time.Duration `name:"pod_label_wait_timeout" default:"10m"` - PodDeletionWaitTimeout time.Duration `name:"pod_deletion_wait_timeout" default:"10m"` - PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"` - SpiloRunAsUser *int64 `json:"spilo_runasuser,omitempty"` - SpiloRunAsGroup *int64 `json:"spilo_runasgroup,omitempty"` - SpiloFSGroup *int64 `name:"spilo_fsgroup"` - PodPriorityClassName string `name:"pod_priority_class_name"` - ClusterDomain string `name:"cluster_domain" default:"cluster.local"` - SpiloPrivileged bool `name:"spilo_privileged" default:"false"` - ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"` - InheritedLabels []string `name:"inherited_labels" default:""` - InheritedAnnotations []string `name:"inherited_annotations" default:""` - DownscalerAnnotations []string `name:"downscaler_annotations"` - ClusterNameLabel string `name:"cluster_name_label" default:"cluster-name"` - DeleteAnnotationDateKey string `name:"delete_annotation_date_key"` - DeleteAnnotationNameKey string `name:"delete_annotation_name_key"` - PodRoleLabel string `name:"pod_role_label" default:"spilo-role"` - PodToleration map[string]string `name:"toleration" default:""` - DefaultCPURequest string `name:"default_cpu_request" default:"100m"` - DefaultMemoryRequest string `name:"default_memory_request" default:"100Mi"` - DefaultCPULimit string `name:"default_cpu_limit" default:"1"` - DefaultMemoryLimit string `name:"default_memory_limit" default:"500Mi"` - MinCPULimit string `name:"min_cpu_limit" default:"250m"` - MinMemoryLimit string `name:"min_memory_limit" default:"250Mi"` - PodEnvironmentConfigMap spec.NamespacedName `name:"pod_environment_configmap"` - PodEnvironmentSecret string `name:"pod_environment_secret"` - NodeReadinessLabel map[string]string `name:"node_readiness_label" default:""` - MaxInstances int32 `name:"max_instances" default:"-1"` - MinInstances int32 `name:"min_instances" default:"-1"` - ShmVolume *bool `name:"enable_shm_volume" default:"true"` + ResourceCheckInterval time.Duration `name:"resource_check_interval" default:"3s"` + ResourceCheckTimeout time.Duration `name:"resource_check_timeout" default:"10m"` + PodLabelWaitTimeout time.Duration `name:"pod_label_wait_timeout" default:"10m"` + PodDeletionWaitTimeout time.Duration `name:"pod_deletion_wait_timeout" default:"10m"` + PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"` + SpiloRunAsUser *int64 `json:"spilo_runasuser,omitempty"` + SpiloRunAsGroup *int64 `json:"spilo_runasgroup,omitempty"` + SpiloFSGroup *int64 `name:"spilo_fsgroup"` + PodPriorityClassName string `name:"pod_priority_class_name"` + ClusterDomain string `name:"cluster_domain" default:"cluster.local"` + SpiloPrivileged bool `name:"spilo_privileged" default:"false"` + AdditionalPodCapabilities []string `name:"additional_pod_capabilities" default:""` + ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"` + InheritedLabels []string `name:"inherited_labels" default:""` + InheritedAnnotations []string `name:"inherited_annotations" default:""` + DownscalerAnnotations []string `name:"downscaler_annotations"` + ClusterNameLabel string `name:"cluster_name_label" default:"cluster-name"` + DeleteAnnotationDateKey string `name:"delete_annotation_date_key"` + DeleteAnnotationNameKey string `name:"delete_annotation_name_key"` + PodRoleLabel string `name:"pod_role_label" default:"spilo-role"` + PodToleration map[string]string `name:"toleration" default:""` + DefaultCPURequest string `name:"default_cpu_request" default:"100m"` + DefaultMemoryRequest string `name:"default_memory_request" default:"100Mi"` + DefaultCPULimit string `name:"default_cpu_limit" default:"1"` + DefaultMemoryLimit string `name:"default_memory_limit" default:"500Mi"` + MinCPULimit string `name:"min_cpu_limit" default:"250m"` + MinMemoryLimit string `name:"min_memory_limit" default:"250Mi"` + PodEnvironmentConfigMap spec.NamespacedName `name:"pod_environment_configmap"` + PodEnvironmentSecret string `name:"pod_environment_secret"` + NodeReadinessLabel map[string]string `name:"node_readiness_label" default:""` + MaxInstances int32 `name:"max_instances" default:"-1"` + MinInstances int32 `name:"min_instances" default:"-1"` + ShmVolume *bool `name:"enable_shm_volume" default:"true"` } type InfrastructureRole struct { From 0cce565b651000639f6758444c12b3397e68c2cf Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Fri, 29 Jan 2021 16:10:27 +0100 Subject: [PATCH 15/26] fix when adding only one capability (#1339) * fix when adding only one capability * fix error messages in unit test --- pkg/cluster/k8sres.go | 2 +- pkg/cluster/k8sres_test.go | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 56500bb29..b1a8adb0b 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -321,7 +321,7 @@ func getLocalAndBoostrapPostgreSQLParameters(parameters map[string]string) (loca } func generateCapabilities(capabilities []string) v1.Capabilities { - if len(capabilities) > 1 { + if len(capabilities) > 0 { additionalCapabilities := []v1.Capability{} for _, capability := range capabilities { additionalCapabilities = append(additionalCapabilities, v1.Capability(strings.ToUpper(capability))) diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index 6034db214..efed071d7 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -1511,13 +1511,21 @@ func TestGenerateCapabilities(t *testing.T) { capabilities: v1.Capabilities{}, err: fmt.Errorf("could not parse empty capabilities configuration"), }, + { + subTest: "configured capability", + configured: []string{"SYS_NICE"}, + capabilities: v1.Capabilities{ + Add: []v1.Capability{"SYS_NICE"}, + }, + err: fmt.Errorf("could not generate one configured capability"), + }, { subTest: "configured capabilities", configured: []string{"SYS_NICE", "CHOWN"}, capabilities: v1.Capabilities{ Add: []v1.Capability{"SYS_NICE", "CHOWN"}, }, - err: fmt.Errorf("could not parse empty capabilities configuration"), + err: fmt.Errorf("could not generate multiple configured capabilities"), }, } for _, tt := range tests { From 2c3cd3ae02fe032d8d1036161318bb5f6c0e7056 Mon Sep 17 00:00:00 2001 From: Aaron Peschel Date: Wed, 3 Feb 2021 05:41:29 -0800 Subject: [PATCH 16/26] Fix CI Pipeline (#1345) This commit attempts to fix the CI issues by upgrading the checkout action to v2. This fix is documented by the coverallsapp upstream. --- .github/workflows/run_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml index d66514a5c..de14267b4 100644 --- a/.github/workflows/run_tests.yaml +++ b/.github/workflows/run_tests.yaml @@ -11,7 +11,7 @@ jobs: name: Unit tests and coverage runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: go-version: "^1.15.6" From 6aeb92f024abfc543a1b49cae37e943c99e0ee1b Mon Sep 17 00:00:00 2001 From: zvier Date: Tue, 9 Feb 2021 16:35:24 +0800 Subject: [PATCH 17/26] code optimization (#1350) * pre-allocate cap for slice structure * if clause is no need because of range, and kubelet also use range method to get each capability so there is no side-effect Signed-off-by: Jeff Zvier --- pkg/cluster/k8sres.go | 15 ++++++--------- pkg/cluster/k8sres_test.go | 4 ++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index b1a8adb0b..3e199e935 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -321,16 +321,13 @@ func getLocalAndBoostrapPostgreSQLParameters(parameters map[string]string) (loca } func generateCapabilities(capabilities []string) v1.Capabilities { - if len(capabilities) > 0 { - additionalCapabilities := []v1.Capability{} - for _, capability := range capabilities { - additionalCapabilities = append(additionalCapabilities, v1.Capability(strings.ToUpper(capability))) - } - return v1.Capabilities{ - Add: additionalCapabilities, - } + additionalCapabilities := make([]v1.Capability, 0, len(capabilities)) + for _, capability := range capabilities { + additionalCapabilities = append(additionalCapabilities, v1.Capability(strings.ToUpper(capability))) + } + return v1.Capabilities{ + Add: additionalCapabilities, } - return v1.Capabilities{} } func nodeAffinity(nodeReadinessLabel map[string]string, nodeAffinity *v1.NodeAffinity) *v1.Affinity { diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index efed071d7..b10123782 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -1502,13 +1502,13 @@ func TestGenerateCapabilities(t *testing.T) { { subTest: "no capabilities", configured: nil, - capabilities: v1.Capabilities{}, + capabilities: v1.Capabilities{Add: []v1.Capability{}}, err: fmt.Errorf("could not parse capabilities configuration of nil"), }, { subTest: "empty capabilities", configured: []string{}, - capabilities: v1.Capabilities{}, + capabilities: v1.Capabilities{Add: []v1.Capability{}}, err: fmt.Errorf("could not parse empty capabilities configuration"), }, { From 4d2b51de415a20e49894c218d0cd49dddfe07551 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Wed, 10 Feb 2021 11:24:24 +0100 Subject: [PATCH 18/26] upgrade pip to latest version to avoid broken deps (#1357) --- docker/logical-backup/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/logical-backup/Dockerfile b/docker/logical-backup/Dockerfile index b84ea2b22..62bd5ce8c 100644 --- a/docker/logical-backup/Dockerfile +++ b/docker/logical-backup/Dockerfile @@ -15,6 +15,7 @@ RUN apt-get update \ gnupg \ gcc \ libffi-dev \ + && pip3 install --upgrade pip \ && pip3 install --no-cache-dir awscli --upgrade \ && pip3 install --no-cache-dir gsutil --upgrade \ && echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list \ From c1c0d5faa144b23421a20d0bc72d1caa451cf631 Mon Sep 17 00:00:00 2001 From: Tommaso Pozzetti <34100051+tommasopozzetti@users.noreply.github.com> Date: Fri, 12 Feb 2021 04:04:23 -0600 Subject: [PATCH 19/26] Fix operator configs runasuser and runasgroup (#1361) This commit fixes a typo in the operator's configuration that would lead to the configs spilo_runasuser and spilo_runasgroup to be ignored. --- pkg/util/config/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 6bc5a6a28..4f4940567 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -28,8 +28,8 @@ type Resources struct { PodLabelWaitTimeout time.Duration `name:"pod_label_wait_timeout" default:"10m"` PodDeletionWaitTimeout time.Duration `name:"pod_deletion_wait_timeout" default:"10m"` PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"` - SpiloRunAsUser *int64 `json:"spilo_runasuser,omitempty"` - SpiloRunAsGroup *int64 `json:"spilo_runasgroup,omitempty"` + SpiloRunAsUser *int64 `name:"spilo_runasuser,omitempty"` + SpiloRunAsGroup *int64 `name:"spilo_runasgroup,omitempty"` SpiloFSGroup *int64 `name:"spilo_fsgroup"` PodPriorityClassName string `name:"pod_priority_class_name"` ClusterDomain string `name:"cluster_domain" default:"cluster.local"` From 772f0ca77188c8904277a0c30f4380af0b3f5462 Mon Sep 17 00:00:00 2001 From: Jan Mussler Date: Fri, 12 Feb 2021 17:36:11 +0100 Subject: [PATCH 20/26] Fix volume sync order. (#1340) --- pkg/cluster/sync.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/cluster/sync.go b/pkg/cluster/sync.go index 5c0f6ce84..0144857b9 100644 --- a/pkg/cluster/sync.go +++ b/pkg/cluster/sync.go @@ -53,6 +53,11 @@ func (c *Cluster) Sync(newSpec *acidv1.Postgresql) error { return err } + // sync volume may already transition volumes to gp3, if iops/throughput or type is specified + if err = c.syncVolumes(); err != nil { + return err + } + if c.OpConfig.EnableEBSGp3Migration { err = c.executeEBSMigration() if nil != err { @@ -60,10 +65,6 @@ func (c *Cluster) Sync(newSpec *acidv1.Postgresql) error { } } - if err = c.syncVolumes(); err != nil { - return err - } - if err = c.enforceMinResourceLimits(&c.Spec); err != nil { err = fmt.Errorf("could not enforce minimum resource limits: %v", err) return err From 17da6bc649e1c733d95217efd8944b811729d533 Mon Sep 17 00:00:00 2001 From: Michael Seiwald Date: Mon, 15 Feb 2021 17:00:21 +0100 Subject: [PATCH 21/26] Truncate cronjob name at 52 characters (#1208) --- pkg/cluster/k8sres.go | 2 +- pkg/cluster/util.go | 9 +++++++++ pkg/cluster/util_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 3e199e935..778318d46 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -2101,7 +2101,7 @@ func (c *Cluster) generateLogicalBackupPodEnvVars() []v1.EnvVar { // getLogicalBackupJobName returns the name; the job itself may not exists func (c *Cluster) getLogicalBackupJobName() (jobName string) { - return c.OpConfig.LogicalBackupJobPrefix + c.clusterName().Name + return trimCronjobName(c.OpConfig.LogicalBackupJobPrefix + c.clusterName().Name) } // Return an array of ownerReferences to make an arbitraty object dependent on diff --git a/pkg/cluster/util.go b/pkg/cluster/util.go index 393a490bd..45045499c 100644 --- a/pkg/cluster/util.go +++ b/pkg/cluster/util.go @@ -576,3 +576,12 @@ func mergeContainers(containers ...[]v1.Container) ([]v1.Container, []string) { } return result, conflicts } + +func trimCronjobName(name string) string { + maxLength := 52 + if len(name) > maxLength { + name = name[0:maxLength] + name = strings.TrimRight(name, "-") + } + return name +} diff --git a/pkg/cluster/util_test.go b/pkg/cluster/util_test.go index 7afc59f28..20214a085 100644 --- a/pkg/cluster/util_test.go +++ b/pkg/cluster/util_test.go @@ -139,3 +139,43 @@ func TestInheritedAnnotations(t *testing.T) { } } + +func Test_trimCronjobName(t *testing.T) { + type args struct { + name string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "short name", + args: args{ + name: "short-name", + }, + want: "short-name", + }, + { + name: "long name", + args: args{ + name: "very-very-very-very-very-very-very-very-very-long-db-name", + }, + want: "very-very-very-very-very-very-very-very-very-long-db", + }, + { + name: "long name should not end with dash", + args: args{ + name: "very-very-very-very-very-very-very-very-very-----------long-db-name", + }, + want: "very-very-very-very-very-very-very-very-very", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := trimCronjobName(tt.args.name); got != tt.want { + t.Errorf("trimCronjobName() = %v, want %v", got, tt.want) + } + }) + } +} From 837f845a1c54a2834a5bb5be27dd3b25007194d3 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Mon, 15 Feb 2021 17:13:07 +0100 Subject: [PATCH 22/26] update kubectl-pg plugin (#1264) * update kubectl-pg plugin * fix remaining build issues and update go modules * some more README updates --- Makefile | 4 +- go.mod | 8 +- go.sum | 129 +++++++- kubectl-pg/README.md | 236 ++++++------- kubectl-pg/cmd/addDb.go | 8 +- kubectl-pg/cmd/addUser.go | 10 +- kubectl-pg/cmd/check.go | 3 +- kubectl-pg/cmd/create.go | 9 +- kubectl-pg/cmd/delete.go | 18 +- kubectl-pg/cmd/extVolume.go | 10 +- kubectl-pg/cmd/list.go | 4 +- kubectl-pg/cmd/logs.go | 14 +- kubectl-pg/cmd/scale.go | 14 +- kubectl-pg/cmd/update.go | 10 +- kubectl-pg/cmd/util.go | 9 +- kubectl-pg/go.mod | 20 +- kubectl-pg/go.sum | 642 ++++++++++++++++++++++++++++-------- kubectl-pg/main.go | 2 +- 18 files changed, 837 insertions(+), 313 deletions(-) diff --git a/Makefile b/Makefile index fe2387670..b9a654dd8 100644 --- a/Makefile +++ b/Makefile @@ -85,7 +85,7 @@ mocks: GO111MODULE=on go generate ./... tools: - GO111MODULE=on go get k8s.io/client-go@kubernetes-1.19.3 + GO111MODULE=on go get k8s.io/client-go@kubernetes-1.20.2 GO111MODULE=on go get github.com/golang/mock/mockgen@v1.4.4 GO111MODULE=on go mod tidy @@ -104,4 +104,4 @@ test: GO111MODULE=on go test ./... e2e: docker # build operator image to be tested - cd e2e; make e2etest \ No newline at end of file + cd e2e; make e2etest diff --git a/go.mod b/go.mod index bbe5140b7..b46ebd089 100644 --- a/go.mod +++ b/go.mod @@ -14,9 +14,9 @@ require ( golang.org/x/mod v0.4.0 // indirect golang.org/x/tools v0.0.0-20201207204333-a835c872fcea // indirect gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.19.4 - k8s.io/apiextensions-apiserver v0.19.3 - k8s.io/apimachinery v0.19.4 - k8s.io/client-go v0.19.3 + k8s.io/api v0.20.2 + k8s.io/apiextensions-apiserver v0.19.4 + k8s.io/apimachinery v0.20.2 + k8s.io/client-go v0.20.2 k8s.io/code-generator v0.19.4 ) diff --git a/go.sum b/go.sum index 64434e2e0..34eeac971 100644 --- a/go.sum +++ b/go.sum @@ -5,24 +5,44 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= 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 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= @@ -100,6 +120,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -107,7 +128,9 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H 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-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -180,15 +203,20 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/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= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -197,6 +225,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 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= @@ -204,6 +234,9 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -211,10 +244,14 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/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/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= @@ -397,6 +434,7 @@ go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -415,13 +453,19 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -430,12 +474,16 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8= @@ -457,10 +505,15 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -471,6 +524,8 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 h1:pE8b58s1HRDMi8RDc79m0HISf9D4TzseP40cEA6IGfs= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -494,31 +549,44 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/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= @@ -541,9 +609,21 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201207204333-a835c872fcea h1:LgKM3cNs8xO6GK1ZVK0nasPn7IN39Sz9EBTwQLyishk= golang.org/x/tools v0.0.0-20201207204333-a835c872fcea/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -556,7 +636,12 @@ google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEt google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -571,7 +656,16 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -582,6 +676,7 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -592,6 +687,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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= @@ -627,36 +724,50 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.19.4 h1:I+1I4cgJYuCDgiLNjKx7SLmIbwgj9w7N7Zr5vSIdwpo= k8s.io/api v0.19.4/go.mod h1:SbtJ2aHCItirzdJ36YslycFNzWADYH3tgOhvBEFtZAk= -k8s.io/apiextensions-apiserver v0.19.3 h1:WZxBypSHW4SdXHbdPTS/Jy7L2la6Niggs8BuU5o+avo= -k8s.io/apiextensions-apiserver v0.19.3/go.mod h1:igVEkrE9TzInc1tYE7qSqxaLg/rEAp6B5+k9Q7+IC8Q= -k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/api v0.20.2 h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw= +k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= +k8s.io/apiextensions-apiserver v0.19.4 h1:D9ak9T012tb3vcGFWYmbQuj9SCC8YM4zhA4XZqsAQC4= +k8s.io/apiextensions-apiserver v0.19.4/go.mod h1:B9rpH/nu4JBCtuUp3zTTk8DEjZUupZTBEec7/2zNRYw= k8s.io/apimachinery v0.19.4 h1:+ZoddM7nbzrDCp0T3SWnyxqf8cbWPT2fkZImoyvHUG0= k8s.io/apimachinery v0.19.4/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apiserver v0.19.3/go.mod h1:bx6dMm+H6ifgKFpCQT/SAhPwhzoeIMlHIaibomUDec0= -k8s.io/client-go v0.19.3 h1:ctqR1nQ52NUs6LpI0w+a5U+xjYwflFwA13OJKcicMxg= -k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= -k8s.io/code-generator v0.19.3/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= +k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg= +k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.19.4/go.mod h1:X8WRHCR1UGZDd7HpV0QDc1h/6VbbpAeAGyxSh8yzZXw= +k8s.io/client-go v0.19.4 h1:85D3mDNoLF+xqpyE9Dh/OtrJDyJrSRKkHmDXIbEzer8= +k8s.io/client-go v0.19.4/go.mod h1:ZrEy7+wj9PjH5VMBCuu/BDlvtUAku0oVFk4MmnW9mWA= +k8s.io/client-go v0.20.2 h1:uuf+iIAbfnCSw8IGAv/Rg0giM+2bOzHLOsbbrwrdhNQ= +k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE= k8s.io/code-generator v0.19.4 h1:c8IL7RgTgJaYgr2bYMgjN0WikHnohbBhEgajfIkuP5I= k8s.io/code-generator v0.19.4/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= -k8s.io/component-base v0.19.3/go.mod h1:WhLWSIefQn8W8jxSLl5WNiR6z8oyMe/8Zywg7alOkRc= +k8s.io/component-base v0.19.4/go.mod h1:ZzuSLlsWhajIDEkKF73j64Gz/5o0AgON08FgRbEPI70= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14 h1:t4L10Qfx/p7ASH3gXCdIUtPbbIuegCoUJf3TMSFekjw= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9 h1:rusRLrDhjBp6aYtl9sGEvQJr6faoHoDLd0YcUBTZguI= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/kubectl-pg/README.md b/kubectl-pg/README.md index c6d4c38ee..78102cf9c 100644 --- a/kubectl-pg/README.md +++ b/kubectl-pg/README.md @@ -1,9 +1,128 @@ # Kubectl Plugin for Zalando's Postgres Operator -## Google Summer of Code 2019 +This plugin is a prototype developed as a part of **Google Summer of Code 2019** under the [Postgres Operator](https://summerofcode.withgoogle.com/archive/2019/organizations/6187982082539520/) organization. -This plugin is a prototype developed as a part of GSoC 2019 under the organisation -**The Postgres Operator** +## Installation of kubectl pg plugin + +This project uses Go Modules for dependency management to build locally. +Install go and enable go modules with ```export GO111MODULE=on```. +From Go >=1.13 Go modules will be enabled by default. + +```bash +# Assumes you have a working KUBECONFIG +$ GO111MODULE="on" +$ GOPATH/src/github.com/zalando/postgres-operator/kubectl-pg go mod vendor +# This generate a vendor directory with all dependencies needed by the plugin. +$ $GOPATH/src/github.com/zalando/postgres-operator/kubectl-pg go install +# This will place the kubectl-pg binary in your $GOPATH/bin +``` + +## Before using the kubectl pg plugin make sure to set KUBECONFIG env variable + +Ideally KUBECONFIG is found in $HOME/.kube/config else specify the KUBECONFIG path here. +```export KUBECONFIG=$HOME/.kube/config``` + +## List all commands available in kubectl pg + +```kubectl pg --help``` (or) ```kubectl pg``` + +## Check if Postgres Operator is installed and running + +```kubectl pg check``` + +## Create a new cluster using manifest file + +```kubectl pg create -f acid-minimal-cluster.yaml``` + +## List postgres resources + +```kubectl pg list``` + +List clusters across namespaces +```kubectl pg list all``` + +## Update existing cluster using manifest file + +```kubectl pg update -f acid-minimal-cluster.yaml``` + +## Delete existing cluster + +Using the manifest file: +```kubectl pg delete -f acid-minimal-cluster.yaml``` + +Or by specifying the cluster name: +```kubectl pg delete acid-minimal-cluster``` + +Use `--namespace` or `-n` flag if your cluster is in a different namespace to where your current context is pointing to: +```kubectl pg delete acid-minimal-cluster -n namespace01``` + +## Adding manifest roles to an existing cluster + +```kubectl pg add-user USER01 -p CREATEDB,LOGIN -c acid-minimal-cluster``` + +Privileges can only be [SUPERUSER, REPLICATION, INHERIT, LOGIN, NOLOGIN, CREATEROLE, CREATEDB, BYPASSURL] +Note: By default, a LOGIN user is created (unless NOLOGIN is specified). + +## Adding databases to an existing cluster + +You have to specify an owner of the new database and this role must already exist in the cluster: +```kubectl pg add-db DB01 -o OWNER01 -c acid-minimal-cluster``` + +## Extend the volume of an existing pg cluster + +```kubectl pg ext-volume 2Gi -c acid-minimal-cluster``` + +## Print the version of Postgres Operator and kubectl pg plugin + +```kubectl pg version``` + +## Connect to the shell of a postgres pod + +Connect to the master pod: +```kubectl pg connect -c CLUSTER -m``` + +Connect to a random replica pod: +```kubectl pg connect -c CLUSTER``` + +Connect to a certain replica pod: +```kubectl pg connect -c CLUSTER -r 0``` + +## Connect to a database via psql + +Adding the `-p` flag allows you to directly connect to a given database with the psql client. +With `-u` you specify the user. If left out the name of the current OS user is taken. +`-d` lets you specify the database. If no database is specified, it will be the same as the user name. + +Connect to `app_db` database on the master with role `app_user`: +```kubectl pg connect -c CLUSTER -m -p -u app_user -d app_db``` + +Connect to the `postgres` database on a random replica with role `postgres`: +```kubectl pg connect -c CLUSTER -p -u postgres``` + +Connect to a certain replica assuming name of OS user, database role and name are all the same: +```kubectl pg connect -c CLUSTER -r 0 -p``` + + +## Access Postgres Operator logs + +```kubectl pg logs -o``` + +## Access Patroni logs of different database pods + +Fetch logs of master: +```kubectl pg logs -c CLUSTER -m``` + +Fetch logs of a random replica pod: +```kubectl pg logs -c CLUSTER``` + +Fetch logs of specified replica +```kubectl pg logs -c CLUSTER -r 2``` + +## Development + +When making changes to the plugin make sure to change the (major/patch) version of plugin in `build.sh` script and run `./build.sh`. + +## Google Summer of Code 2019 ### GSoC Proposal @@ -13,113 +132,6 @@ This plugin is a prototype developed as a part of GSoC 2019 under the organisati https://github.com/VineethReddy02/GSoC-Kubectl-Plugin-for-Postgres-Operator-tracker - ### Final Project Report - - https://gist.github.com/VineethReddy02/159283bd368a710379eaf0f6bd60a40a - +### Final Project Report -### Installtion of kubectl pg plugin - -This project uses Go Modules for dependency management to build locally -Install go and enable go modules ```export GO111MODULE=on``` -From Go >=1.13 Go modules will be enabled by default -``` -# Assumes you have a working KUBECONFIG -$ GO111MODULE="on" -# As of now go by default doesn't support Go mods. So explicit enabling is required. -$ GOPATH/src/github.com/zalando/postgres-operator/kubectl-pg go mod vendor -# This generate a vendor directory with all dependencies needed by the plugin. -$ $GOPATH/src/github.com/zalando/postgres-operator/kubectl-pg go install -# This will place the kubectl-pg binary in your $GOPATH/bin -``` - -### Before using the kubectl pg plugin make sure to set KUBECONFIG env varibale - -Ideally KUBECONFIG is found in $HOME/.kube/config else specify the KUBECONFIG path here. - -```export KUBECONFIG=$HOME/.kube/config``` - -### To list all commands available in kubectl pg - -```kubectl pg --help``` (or) ```kubectl pg``` - -### This basically means the operator pod managed to start, so our operator is installed. - -```kubectl pg check``` - -### To create postgresql cluster using manifest file - -```kubectl pg create -f acid-minimal-cluster.yaml``` - -### To update existing cluster using manifest file - -```kubectl pg update -f acid-minimal-cluster.yaml``` - -### To delete existing cluster using manifest file - -```kubectl pg delete -f acid-minimal-cluster.yaml``` - -### To delete existing cluster using cluster name - -```kubectl pg delete acid-minimal-cluster``` - ---namespace or -n flag to specify namespace if cluster is in other namespace. - -```kubectl pg delete acid-minimal-cluster -n namespace01``` - -### To list postgres resources for the current namespace - -```kubectl pg list``` - -### To list postgres resources across namespaces - -```kubectl pg list all``` - -### To add-user and it's roles to an existing pg cluster - -```kubectl pg add-user USER01 -p CREATEDB,LOGIN -c acid-minimal-cluster``` - -Privileges can only be [SUPERUSER, REPLICATION, INHERIT, LOGIN, NOLOGIN, CREATEROLE, CREATEDB, BYPASSURL] - -Note: A login user is created by default unless NOLOGIN is specified, in which case the operator creates a role. - -### To add-db and it's owner to an existing pg cluster - -```kubectl pg add-db DB01 -o OWNER01 -c acid-minimal-cluster``` - -### To extend volume for an existing pg cluster - -```kubectl pg ext-volume 2Gi -c acid-minimal-cluster``` - -### To find the version of postgres operator and kubectl plugin - -```kubectl pg version (optional -n NAMESPACE allows to know specific to a namespace)``` - -### To connect to the shell of a postgres pod - -```kubectl pg connect -c CLUSTER``` #This connects to a random pod -```kubectl pg connect -c CLUSTER -m``` #This connects the master -```kubectl pg connect -c CLUSTER -r 0``` #This connects to the desired replica - -### To connect to the psql prompt - -```kubectl pg connect -c CLUSTER -p -u username``` #This connects to a random pod. Not master -```kubectl pg connect -c CLUSTER -m -p -u username``` #This connects the master -```kubectl pg connect -c CLUSTER -r 0 -p -u username``` #This connects to the desired replica - -Note: -p represents psql prompt - -### To get the logs of postgres operator - -```kubectl pg logs -o``` - -### To get the logs of the postgres cluster - -```kubectl pg logs -c CLUSTER``` #Fetches the logs of a random pod. Not master -```kubectl pg logs -c CLUSTER -m``` #Fetches the logs of master -```kubectl pg logs -c CLUSTER -r 2``` #Fecthes the logs of specified replica - -## Development - -- When making changes to plugin make sure to change the major or patch version -of plugin in ```build.sh``` and run ```./build.sh``` +https://gist.github.com/VineethReddy02/159283bd368a710379eaf0f6bd60a40a diff --git a/kubectl-pg/cmd/addDb.go b/kubectl-pg/cmd/addDb.go index 1da426703..cd45ea974 100644 --- a/kubectl-pg/cmd/addDb.go +++ b/kubectl-pg/cmd/addDb.go @@ -23,13 +23,15 @@ THE SOFTWARE. package cmd import ( + "context" "encoding/json" "fmt" + "log" + "github.com/spf13/cobra" PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "log" ) // addDbCmd represents the addDb command @@ -62,7 +64,7 @@ func addDb(dbName string, dbOwner string, clusterName string) { } namespace := getCurrentNamespace() - postgresql, err := postgresConfig.Postgresqls(namespace).Get(clusterName, metav1.GetOptions{}) + postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{}) if err != nil { log.Fatal(err) } @@ -84,7 +86,7 @@ func addDb(dbName string, dbOwner string, clusterName string) { log.Fatal("The provided db-name is reserved by postgres") } - updatedPostgres, err := postgresConfig.Postgresqls(namespace).Patch(postgresql.Name, types.MergePatchType, patch, "") + updatedPostgres, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/addUser.go b/kubectl-pg/cmd/addUser.go index df38c44b8..288af0836 100644 --- a/kubectl-pg/cmd/addUser.go +++ b/kubectl-pg/cmd/addUser.go @@ -23,14 +23,16 @@ THE SOFTWARE. package cmd import ( + "context" "encoding/json" "fmt" + "log" + "strings" + "github.com/spf13/cobra" PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "log" - "strings" ) var allowedPrivileges = []string{"SUPERUSER", "REPLICATION", "INHERIT", "LOGIN", "NOLOGIN", "CREATEROLE", "CREATEDB", "BYPASSURL"} @@ -90,7 +92,7 @@ func addUser(user string, clusterName string, permissions []string) { } namespace := getCurrentNamespace() - postgresql, err := postgresConfig.Postgresqls(namespace).Get(clusterName, metav1.GetOptions{}) + postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{}) if err != nil { log.Fatal(err) } @@ -114,7 +116,7 @@ func addUser(user string, clusterName string, permissions []string) { } patch := applyUserPatch(user, Privileges) - updatedPostgresql, err := postgresConfig.Postgresqls(namespace).Patch(postgresql.Name, types.MergePatchType, patch, "") + updatedPostgresql, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/check.go b/kubectl-pg/cmd/check.go index 4f88e7efa..6068c35bb 100644 --- a/kubectl-pg/cmd/check.go +++ b/kubectl-pg/cmd/check.go @@ -23,6 +23,7 @@ THE SOFTWARE. package cmd import ( + "context" "fmt" "log" @@ -55,7 +56,7 @@ func check() *v1.CustomResourceDefinition { log.Fatal(err) } - crdInfo, err := apiExtClient.CustomResourceDefinitions().Get(postgresConstants.PostgresCRDResouceName, metav1.GetOptions{}) + crdInfo, err := apiExtClient.CustomResourceDefinitions().Get(context.TODO(), postgresConstants.PostgresCRDResouceName, metav1.GetOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/create.go b/kubectl-pg/cmd/create.go index 2ed7b50c0..4d1bc75fb 100644 --- a/kubectl-pg/cmd/create.go +++ b/kubectl-pg/cmd/create.go @@ -23,13 +23,16 @@ THE SOFTWARE. package cmd import ( + "context" "fmt" + "io/ioutil" + "log" + "github.com/spf13/cobra" v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1" - "io/ioutil" "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" - "log" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // createCmd kubectl pg create. @@ -62,7 +65,7 @@ func create(fileName string) { } postgresSql := obj.(*v1.Postgresql) - _, err = postgresConfig.Postgresqls(postgresSql.Namespace).Create(postgresSql) + _, err = postgresConfig.Postgresqls(postgresSql.Namespace).Create(context.TODO(), postgresSql, metav1.CreateOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/delete.go b/kubectl-pg/cmd/delete.go index 3f51c2128..7737212b9 100644 --- a/kubectl-pg/cmd/delete.go +++ b/kubectl-pg/cmd/delete.go @@ -23,14 +23,16 @@ THE SOFTWARE. package cmd import ( + "context" "fmt" - "github.com/spf13/cobra" - "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" - PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1" "io/ioutil" + "log" + + "github.com/spf13/cobra" + v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" + PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1" "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "log" ) // deleteCmd represents kubectl pg delete. @@ -87,7 +89,7 @@ func deleteByFile(file string) { } postgresSql := obj.(*v1.Postgresql) - _, err = postgresConfig.Postgresqls(postgresSql.Namespace).Get(postgresSql.Name, metav1.GetOptions{}) + _, err = postgresConfig.Postgresqls(postgresSql.Namespace).Get(context.TODO(), postgresSql.Name, metav1.GetOptions{}) if err != nil { fmt.Printf("Postgresql %s not found with the provided namespace %s : %s \n", postgresSql.Name, postgresSql.Namespace, err) return @@ -95,7 +97,7 @@ func deleteByFile(file string) { fmt.Printf("Are you sure you want to remove this PostgreSQL cluster? If so, please type (%s/%s) and hit Enter\n", postgresSql.Namespace, postgresSql.Name) confirmAction(postgresSql.Name, postgresSql.Namespace) - err = postgresConfig.Postgresqls(postgresSql.Namespace).Delete(postgresSql.Name, &metav1.DeleteOptions{}) + err = postgresConfig.Postgresqls(postgresSql.Namespace).Delete(context.TODO(), postgresSql.Name, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } @@ -109,7 +111,7 @@ func deleteByName(clusterName string, namespace string) { log.Fatal(err) } - _, err = postgresConfig.Postgresqls(namespace).Get(clusterName, metav1.GetOptions{}) + _, err = postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{}) if err != nil { fmt.Printf("Postgresql %s not found with the provided namespace %s : %s \n", clusterName, namespace, err) return @@ -117,7 +119,7 @@ func deleteByName(clusterName string, namespace string) { fmt.Printf("Are you sure you want to remove this PostgreSQL cluster? If so, please type (%s/%s) and hit Enter\n", namespace, clusterName) confirmAction(clusterName, namespace) - err = postgresConfig.Postgresqls(namespace).Delete(clusterName, &metav1.DeleteOptions{}) + err = postgresConfig.Postgresqls(namespace).Delete(context.TODO(), clusterName, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/extVolume.go b/kubectl-pg/cmd/extVolume.go index 351876c68..58a9eef67 100644 --- a/kubectl-pg/cmd/extVolume.go +++ b/kubectl-pg/cmd/extVolume.go @@ -23,15 +23,17 @@ THE SOFTWARE. package cmd import ( + "context" "encoding/json" "fmt" + "log" + "strconv" + "github.com/spf13/cobra" PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "log" - "strconv" ) // extVolumeCmd represents the extVolume command @@ -63,7 +65,7 @@ func extVolume(increasedVolumeSize string, clusterName string) { } namespace := getCurrentNamespace() - postgresql, err := postgresConfig.Postgresqls(namespace).Get(clusterName, metav1.GetOptions{}) + postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{}) if err != nil { log.Fatalf("hii %v", err) } @@ -86,7 +88,7 @@ func extVolume(increasedVolumeSize string, clusterName string) { if newSize.Value() > oldSize.Value() { patchInstances := volumePatch(newSize) - response, err := postgresConfig.Postgresqls(namespace).Patch(postgresql.Name, types.MergePatchType, patchInstances, "") + response, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patchInstances, metav1.PatchOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/list.go b/kubectl-pg/cmd/list.go index f4dea882d..4fd6de3ba 100644 --- a/kubectl-pg/cmd/list.go +++ b/kubectl-pg/cmd/list.go @@ -23,6 +23,7 @@ THE SOFTWARE. package cmd import ( + "context" "fmt" "log" "strconv" @@ -70,8 +71,7 @@ func list(allNamespaces bool, namespace string) { log.Fatal(err) } - var listPostgres *v1.PostgresqlList - listPostgres, err = postgresConfig.Postgresqls(namespace).List(metav1.ListOptions{}) + listPostgres, err := postgresConfig.Postgresqls(namespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/logs.go b/kubectl-pg/cmd/logs.go index b527b6c52..21a4fd6ec 100644 --- a/kubectl-pg/cmd/logs.go +++ b/kubectl-pg/cmd/logs.go @@ -23,12 +23,14 @@ THE SOFTWARE. package cmd import ( - "github.com/spf13/cobra" + "context" "io" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" "log" "os" + + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" ) // logsCmd represents the logs command @@ -71,7 +73,7 @@ func operatorLogs() { } operator := getPostgresOperator(client) - allPods, err := client.CoreV1().Pods(operator.Namespace).List(metav1.ListOptions{}) + allPods, err := client.CoreV1().Pods(operator.Namespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { log.Fatal(err) } @@ -93,7 +95,7 @@ func operatorLogs() { Param("follow", "--follow"). Param("container", OperatorName) - readCloser, err := execRequest.Stream() + readCloser, err := execRequest.Stream(context.TODO()) if err != nil { log.Fatal(err) } @@ -120,7 +122,7 @@ func clusterLogs(clusterName string, master bool, replica string) { Param("follow", "--follow"). Param("container", "postgres") - readCloser, err := execRequest.Stream() + readCloser, err := execRequest.Stream(context.TODO()) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/scale.go b/kubectl-pg/cmd/scale.go index d273bbd6f..5e8848de6 100644 --- a/kubectl-pg/cmd/scale.go +++ b/kubectl-pg/cmd/scale.go @@ -23,8 +23,12 @@ THE SOFTWARE. package cmd import ( + "context" "encoding/json" "fmt" + "log" + "strconv" + "github.com/spf13/cobra" PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1" v1 "k8s.io/api/apps/v1" @@ -32,8 +36,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - "log" - "strconv" ) // scaleCmd represents the scale command @@ -76,7 +78,7 @@ func scale(numberOfInstances int32, clusterName string, namespace string) { log.Fatal(err) } - postgresql, err := postgresConfig.Postgresqls(namespace).Get(clusterName, metav1.GetOptions{}) + postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{}) if err != nil { log.Fatal(err) } @@ -100,7 +102,7 @@ func scale(numberOfInstances int32, clusterName string, namespace string) { } patchInstances := scalePatch(numberOfInstances) - UpdatedPostgres, err := postgresConfig.Postgresqls(namespace).Patch(postgresql.Name, types.MergePatchType, patchInstances, "") + UpdatedPostgres, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patchInstances, metav1.PatchOptions{}) if err != nil { log.Fatal(err) } @@ -145,7 +147,7 @@ func allowedMinMaxInstances(config *rest.Config) (int32, int32) { } if operatorConfigName == "" { - configMap, err := k8sClient.CoreV1().ConfigMaps(operator.Namespace).Get(configMapName, metav1.GetOptions{}) + configMap, err := k8sClient.CoreV1().ConfigMaps(operator.Namespace).Get(context.TODO(), configMapName, metav1.GetOptions{}) if err != nil { log.Fatal(err) } @@ -172,7 +174,7 @@ func allowedMinMaxInstances(config *rest.Config) (int32, int32) { log.Fatal(err) } - operatorConfig, err := pgClient.OperatorConfigurations(operator.Namespace).Get(operatorConfigName, metav1.GetOptions{}) + operatorConfig, err := pgClient.OperatorConfigurations(operator.Namespace).Get(context.TODO(), operatorConfigName, metav1.GetOptions{}) if err != nil { log.Fatalf("unable to read operator configuration %v", err) } diff --git a/kubectl-pg/cmd/update.go b/kubectl-pg/cmd/update.go index 6efdb8b8c..604d613fc 100644 --- a/kubectl-pg/cmd/update.go +++ b/kubectl-pg/cmd/update.go @@ -23,14 +23,16 @@ THE SOFTWARE. package cmd import ( + "context" "fmt" + "io/ioutil" + "log" + "github.com/spf13/cobra" v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1" - "io/ioutil" "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "log" ) // updateCmd represents kubectl pg update @@ -67,13 +69,13 @@ func updatePgResources(fileName string) { } newPostgresObj := obj.(*v1.Postgresql) - oldPostgresObj, err := postgresConfig.Postgresqls(newPostgresObj.Namespace).Get(newPostgresObj.Name, metav1.GetOptions{}) + oldPostgresObj, err := postgresConfig.Postgresqls(newPostgresObj.Namespace).Get(context.TODO(), newPostgresObj.Name, metav1.GetOptions{}) if err != nil { log.Fatal(err) } newPostgresObj.ResourceVersion = oldPostgresObj.ResourceVersion - response, err := postgresConfig.Postgresqls(newPostgresObj.Namespace).Update(newPostgresObj) + response, err := postgresConfig.Postgresqls(newPostgresObj.Namespace).Update(context.TODO(), newPostgresObj, metav1.UpdateOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/cmd/util.go b/kubectl-pg/cmd/util.go index a2a5c2073..a6bc10296 100644 --- a/kubectl-pg/cmd/util.go +++ b/kubectl-pg/cmd/util.go @@ -23,6 +23,7 @@ THE SOFTWARE. package cmd import ( + "context" "flag" "fmt" "log" @@ -108,7 +109,7 @@ func getPodName(clusterName string, master bool, replicaNumber string) string { log.Fatal(err) } - postgresCluster, err := postgresConfig.Postgresqls(getCurrentNamespace()).Get(clusterName, metav1.GetOptions{}) + postgresCluster, err := postgresConfig.Postgresqls(getCurrentNamespace()).Get(context.TODO(), clusterName, metav1.GetOptions{}) if err != nil { log.Fatal(err) } @@ -119,7 +120,7 @@ func getPodName(clusterName string, master bool, replicaNumber string) string { replica := clusterName + "-" + replicaNumber for ins := 0; ins < int(numOfInstances); ins++ { - pod, err := client.CoreV1().Pods(getCurrentNamespace()).Get(clusterName+"-"+strconv.Itoa(ins), metav1.GetOptions{}) + pod, err := client.CoreV1().Pods(getCurrentNamespace()).Get(context.TODO(), clusterName+"-"+strconv.Itoa(ins), metav1.GetOptions{}) if err != nil { log.Fatal(err) } @@ -143,13 +144,13 @@ func getPodName(clusterName string, master bool, replicaNumber string) string { func getPostgresOperator(k8sClient *kubernetes.Clientset) *v1.Deployment { var operator *v1.Deployment - operator, err := k8sClient.AppsV1().Deployments(getCurrentNamespace()).Get(OperatorName, metav1.GetOptions{}) + operator, err := k8sClient.AppsV1().Deployments(getCurrentNamespace()).Get(context.TODO(), OperatorName, metav1.GetOptions{}) if err == nil { return operator } allDeployments := k8sClient.AppsV1().Deployments("") - listDeployments, err := allDeployments.List(metav1.ListOptions{}) + listDeployments, err := allDeployments.List(context.TODO(), metav1.ListOptions{}) if err != nil { log.Fatal(err) } diff --git a/kubectl-pg/go.mod b/kubectl-pg/go.mod index bf1591beb..6e732936e 100644 --- a/kubectl-pg/go.mod +++ b/kubectl-pg/go.mod @@ -1,14 +1,14 @@ -module kubectl-pg +module github.com/zalando/postgres-operator/kubectl-pg -go 1.12 +go 1.15 require ( - github.com/imdario/mergo v0.3.7 // indirect - github.com/kisielk/errcheck v1.2.0 // indirect - github.com/spf13/cobra v0.0.5 - github.com/spf13/viper v1.4.0 - github.com/zalando/postgres-operator v1.2.0 - k8s.io/apiextensions-apiserver v0.0.0-20190726024412-102230e288fd - k8s.io/apimachinery v0.0.0-20190727130956-f97a4e5b4abc - k8s.io/client-go v0.0.0-20190726023111-a9c895e7f2ac + github.com/spf13/cobra v1.1.3 + github.com/spf13/viper v1.7.1 + github.com/zalando/postgres-operator v1.6.0 + k8s.io/api v0.20.2 + k8s.io/apiextensions-apiserver v0.20.2 + k8s.io/apimachinery v0.20.2 + k8s.io/client-go v0.20.2 + k8s.io/klog v1.0.0 // indirect ) diff --git a/kubectl-pg/go.sum b/kubectl-pg/go.sum index 81ace7f42..c161c44b8 100644 --- a/kubectl-pg/go.sum +++ b/kubectl-pg/go.sum @@ -1,7 +1,49 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= 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= @@ -11,60 +53,88 @@ github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/VineethReddy02/postgres-operator v1.1.0 h1:I1CyYLrPbI78blfQY5Dy7m9TNsVVvCNXSM9rEKh888Q= +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/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 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.36.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= 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/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 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/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+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 v0.0.0-20180117170138-065b426bd416/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +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-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 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= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -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/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +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-20180725130230-947c36da3153/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/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/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-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= 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= @@ -72,143 +142,244 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ 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/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +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/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +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/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +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/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +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 v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v0.0.0-20190410021324-65acae22fc9/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/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/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 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/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +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/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -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/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/google/uuid v1.1.2/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/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.4 h1:ynbQIWjLw7iv6HAFdixb30U7Uvcmx+f4KlLJpmhkTK0= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +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/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +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.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +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/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 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 v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 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/konsorten/go-windows-terminal-sequences v1.0.3/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/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 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/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +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/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +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/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +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.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 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/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 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.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 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/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/r3labs/diff v1.1.0/go.mod h1:7WjXasNzi0vJetRcB/RqNl5dlIsmXcTTLmF5IoH6Xig= 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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 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/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -216,171 +387,382 @@ github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.4/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -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/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= 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/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= +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.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 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= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +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/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -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= -github.com/zalando/postgres-operator v1.2.0 h1:XV3zM2iON4O8iqLTlSNeekxIqistnUx7Btfk2w7mDaY= -github.com/zalando/postgres-operator v1.2.0/go.mod h1:0+dT6DbKj6yvytwBpApmSwEbMBqbLS9AzgUZacbG0lY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zalando/postgres-operator v1.6.0 h1:Nypf6vO9T6NA1+PTGun7Oz0dEMCZH6NYp6vtyss/XM0= +github.com/zalando/postgres-operator v1.6.0/go.mod h1:gQC+cdbxdh9YpjDVWLHFgu7/xNVO/GDvTXZaBC1Qv2Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +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.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/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/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 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-20181025213731-e84da0312774/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= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/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-20190206173232-65e2d4e15006/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20181026203630-95b1ffbd15a5/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= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/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-20190206041539-40960b6deb8e/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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -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/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201207204333-a835c872fcea/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 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/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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/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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A= -k8s.io/api v0.0.0-20190726022912-69e1bce1dad5 h1:vSfC/FjyeuqXC/fjdNqZixNpeec4mEHJ68K3kzetm/M= -k8s.io/api v0.0.0-20190726022912-69e1bce1dad5/go.mod h1:V6cpJ9D7WqSy0wqcE096gcbj+W//rshgQgmj1Shdwi8= -k8s.io/apiextensions-apiserver v0.0.0-20190726024412-102230e288fd h1:qnJFeJfmqE4nGI+xUjLsSzpl5o08JkRGttSIfzfqj7U= -k8s.io/apiextensions-apiserver v0.0.0-20190726024412-102230e288fd/go.mod h1:sDyIzs1dBO19o8gtqZK79kPQ+OIyjo34y2Gh2O+2MMo= -k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA= -k8s.io/apimachinery v0.0.0-20190726022757-641a75999153/go.mod h1:eXR4ljjmbwK6Ng0PKsXRySPXnTUy/qBUa6kPDeckhQ0= -k8s.io/apimachinery v0.0.0-20190727130956-f97a4e5b4abc h1:fi1vG9UrnqoGU/H2HP2rr7GH6vaQeFdLxfocg5uMQmA= -k8s.io/apimachinery v0.0.0-20190727130956-f97a4e5b4abc/go.mod h1:eXR4ljjmbwK6Ng0PKsXRySPXnTUy/qBUa6kPDeckhQ0= -k8s.io/apiserver v0.0.0-20190726023815-781c3cd1b3dc/go.mod h1:Gy8ElOsvjzEZF7lUFUffGBuA6Vg4qsN/r+vt05szn6c= -k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g= -k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k= -k8s.io/client-go v0.0.0-20190726023111-a9c895e7f2ac h1:wqRgq2VyWMCJW9mU9MIMAPj5jBOjFFQYbT/DydDUo94= -k8s.io/client-go v0.0.0-20190726023111-a9c895e7f2ac/go.mod h1:ncT9fCvHnM5BUiZs0RCf9vAEqRrRoJtR2sZ2evompEU= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/api v0.19.4/go.mod h1:SbtJ2aHCItirzdJ36YslycFNzWADYH3tgOhvBEFtZAk= +k8s.io/api v0.20.2 h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw= +k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= +k8s.io/apiextensions-apiserver v0.19.3/go.mod h1:igVEkrE9TzInc1tYE7qSqxaLg/rEAp6B5+k9Q7+IC8Q= +k8s.io/apiextensions-apiserver v0.20.2 h1:rfrMWQ87lhd8EzQWRnbQ4gXrniL/yTRBgYH1x1+BLlo= +k8s.io/apiextensions-apiserver v0.20.2/go.mod h1:F6TXp389Xntt+LUq3vw6HFOLttPa0V8821ogLGwb6Zs= +k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.19.4/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg= +k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.19.3/go.mod h1:bx6dMm+H6ifgKFpCQT/SAhPwhzoeIMlHIaibomUDec0= +k8s.io/apiserver v0.20.2/go.mod h1:2nKd93WyMhZx4Hp3RfgH2K5PhwyTrprrkWYnI7id7jA= +k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/client-go v0.20.2 h1:uuf+iIAbfnCSw8IGAv/Rg0giM+2bOzHLOsbbrwrdhNQ= +k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE= +k8s.io/client-go v1.5.1 h1:XaX/lo2/u3/pmFau8HN+sB5C/b4dc4Dmm2eXjBH4p1E= 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-20190726022633-14ba7d03f06f/go.mod h1:kr7tMYxZEaP3mrijPwXnhxOvPyqdJw6TZH87KfFboQ0= -k8s.io/component-base v0.0.0-20190726023549-042c00bc1f9e/go.mod h1:KiJFR5KR5yaKNXFgCliO2CPcmAI6hdZCcb5XZyl0EhQ= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/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.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68= -k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= -k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= -k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a h1:2jUDc9gJja832Ftp+QbDV0tVhQHMISFn01els+2ZAcw= -k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a/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-20190719182312-e94e05bfbbe3/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +k8s.io/code-generator v0.19.3/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= +k8s.io/code-generator v0.19.4/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= +k8s.io/code-generator v0.20.2/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= +k8s.io/component-base v0.19.3/go.mod h1:WhLWSIefQn8W8jxSLl5WNiR6z8oyMe/8Zywg7alOkRc= +k8s.io/component-base v0.20.2/go.mod h1:pzFtCiwe/ASD0iV7ySMu8SYVJjCapNM9bjvk7ptpKh0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +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/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/kubectl-pg/main.go b/kubectl-pg/main.go index fb4ad3d5e..bfcd5eb29 100644 --- a/kubectl-pg/main.go +++ b/kubectl-pg/main.go @@ -23,7 +23,7 @@ THE SOFTWARE. package main import ( - "kubectl-pg/cmd" + "github.com/zalando/postgres-operator/kubectl-pg/cmd" ) func main() { From 137fbbf41e5fbbf1fd6625eb779b9ee8dccafba9 Mon Sep 17 00:00:00 2001 From: balibebas <65664227+balibebas@users.noreply.github.com> Date: Tue, 16 Feb 2021 00:22:25 +0800 Subject: [PATCH 23/26] update quickstart to add k3d (#1334) --- docs/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index 86d2fabbf..fe083a61d 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -11,7 +11,7 @@ solutions: * [minikube](https://github.com/kubernetes/minikube/releases), which creates a single-node K8s cluster inside a VM (requires KVM or VirtualBox), -* [kind](https://kind.sigs.k8s.io/), which allows creating multi-nodes K8s +* [kind](https://kind.sigs.k8s.io/) and [k3d](https://k3d.io), which allows creating multi-nodes K8s clusters running on Docker (requires Docker) To interact with the K8s infrastructure install it's CLI runtime [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-via-curl). From 41858a702ce678ee05351f58d942628f2b0f4426 Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Tue, 16 Feb 2021 10:38:20 +0100 Subject: [PATCH 24/26] making pgTeamMap a pointer (#1349) * making pgTeamMap a pointer * init empty map * add e2e test for additional teams and members * update test_min_resource_limits * add more waiting in node_affinity_test * no need for pointers in map of postgresTeamMebership * another minor update on node affinity test * refactor and fix fetching additional members --- e2e/tests/test_e2e.py | 170 +++++++++++++++++++++++--------- pkg/cluster/cluster.go | 20 ++-- pkg/cluster/util.go | 21 +++- pkg/controller/controller.go | 3 +- pkg/controller/util.go | 6 +- pkg/teams/postgres_team.go | 3 + pkg/teams/postgres_team_test.go | 57 +++++------ 7 files changed, 185 insertions(+), 95 deletions(-) diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 87bed3baa..2300ebfe3 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -126,6 +126,7 @@ class EndToEndTestCase(unittest.TestCase): "api-service.yaml", "infrastructure-roles.yaml", "infrastructure-roles-new.yaml", + "custom-team-membership.yaml", "e2e-storage-class.yaml"]: result = k8s.create_with_kubectl("manifests/" + filename) print("stdout: {}, stderr: {}".format(result.stdout, result.stderr)) @@ -174,6 +175,63 @@ class EndToEndTestCase(unittest.TestCase): self.eventuallyEqual(lambda: self.k8s.count_pods_with_container_capabilities(capabilities, cluster_label), 2, "Container capabilities not updated") + @timeout_decorator.timeout(TEST_TIMEOUT_SEC) + def test_additional_teams_and_members(self): + ''' + Test PostgresTeam CRD with extra teams and members + ''' + # enable PostgresTeam CRD and lower resync + enable_postgres_team_crd = { + "data": { + "enable_postgres_team_crd": "true", + "resync_period": "15s", + }, + } + self.k8s.update_config(enable_postgres_team_crd) + self.eventuallyEqual(lambda: self.k8s.get_operator_state(), {"0": "idle"}, + "Operator does not get in sync") + + self.k8s.api.custom_objects_api.patch_namespaced_custom_object( + 'acid.zalan.do', 'v1', 'default', + 'postgresteams', 'custom-team-membership', + { + 'spec': { + 'additionalTeams': { + 'acid': [ + 'e2e' + ] + }, + 'additionalMembers': { + 'e2e': [ + 'kind' + ] + } + } + }) + + # make sure we let one sync pass and the new user being added + time.sleep(15) + + leader = self.k8s.get_cluster_leader_pod('acid-minimal-cluster') + user_query = """ + SELECT usename + FROM pg_catalog.pg_user + WHERE usename IN ('elephant', 'kind'); + """ + users = self.query_database(leader.metadata.name, "postgres", user_query) + self.eventuallyEqual(lambda: len(users), 2, + "Not all additional users found in database: {}".format(users)) + + # revert config change + revert_resync = { + "data": { + "resync_period": "30m", + }, + } + self.k8s.update_config(revert_resync) + self.eventuallyEqual(lambda: self.k8s.get_operator_state(), {"0": "idle"}, + "Operator does not get in sync") + @timeout_decorator.timeout(TEST_TIMEOUT_SEC) def test_overwrite_pooler_deployment(self): self.k8s.create_with_kubectl("manifests/minimal-fake-pooler-deployment.yaml") @@ -332,54 +390,19 @@ class EndToEndTestCase(unittest.TestCase): # Verify that all the databases have pooler schema installed. # Do this via psql, since otherwise we need to deal with # credentials. - dbList = [] + db_list = [] leader = k8s.get_cluster_leader_pod('acid-minimal-cluster') - dbListQuery = "select datname from pg_database" - schemasQuery = """ + schemas_query = """ select schema_name from information_schema.schemata where schema_name = 'pooler' """ - exec_query = r"psql -tAq -c \"{}\" -d {}" - if leader: - try: - q = exec_query.format(dbListQuery, "postgres") - q = "su postgres -c \"{}\"".format(q) - print('Get databases: {}'.format(q)) - result = k8s.exec_with_kubectl(leader.metadata.name, q) - dbList = clean_list(result.stdout.split(b'\n')) - print('dbList: {}, stdout: {}, stderr {}'.format( - dbList, result.stdout, result.stderr - )) - except Exception as ex: - print('Could not get databases: {}'.format(ex)) - print('Stdout: {}'.format(result.stdout)) - print('Stderr: {}'.format(result.stderr)) - - for db in dbList: - if db in ('template0', 'template1'): - continue - - schemas = [] - try: - q = exec_query.format(schemasQuery, db) - q = "su postgres -c \"{}\"".format(q) - print('Get schemas: {}'.format(q)) - result = k8s.exec_with_kubectl(leader.metadata.name, q) - schemas = clean_list(result.stdout.split(b'\n')) - print('schemas: {}, stdout: {}, stderr {}'.format( - schemas, result.stdout, result.stderr - )) - except Exception as ex: - print('Could not get databases: {}'.format(ex)) - print('Stdout: {}'.format(result.stdout)) - print('Stderr: {}'.format(result.stderr)) - - self.assertNotEqual(len(schemas), 0) - else: - print('Could not find leader pod') + db_list = self.list_databases(leader.metadata.name) + for db in db_list: + self.eventuallyNotEqual(lambda: len(self.query_database(leader.metadata.name, db, schemas_query)), 0, + "Pooler schema not found in database {}".format(db)) # remove config section to make test work next time k8s.api.custom_objects_api.patch_namespaced_custom_object( @@ -690,6 +713,7 @@ class EndToEndTestCase(unittest.TestCase): "min_memory_limit": minMemoryLimit } } + k8s.update_config(patch_min_resource_limits, "Minimum resource test") # lower resource limits below minimum pg_patch_resources = { @@ -707,10 +731,8 @@ class EndToEndTestCase(unittest.TestCase): } } k8s.api.custom_objects_api.patch_namespaced_custom_object( - "acid.zalan.do", "v1", "default", "postgresqls", "acid-minimal-cluster", pg_patch_resources) - - k8s.patch_statefulset({"metadata": {"annotations": {"zalando-postgres-operator-rolling-update-required": "False"}}}) - k8s.update_config(patch_min_resource_limits, "Minimum resource test") + "acid.zalan.do", "v1", "default", "postgresqls", "acid-minimal-cluster", pg_patch_resources) + self.eventuallyEqual(lambda: k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") self.eventuallyEqual(lambda: k8s.count_running_pods(), 2, "No two pods running after lazy rolling upgrade") self.eventuallyEqual(lambda: len(k8s.get_patroni_running_members()), 2, "Postgres status did not enter running") @@ -967,7 +989,6 @@ class EndToEndTestCase(unittest.TestCase): # verify we are in good state from potential previous tests self.eventuallyEqual(lambda: k8s.count_running_pods(), 2, "No 2 pods running") self.eventuallyEqual(lambda: len(k8s.get_patroni_running_members("acid-minimal-cluster-0")), 2, "Postgres status did not enter running") - self.eventuallyEqual(lambda: self.k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") # get nodes of master and replica(s) master_node, replica_nodes = k8s.get_pg_nodes(cluster_label) @@ -1053,6 +1074,9 @@ class EndToEndTestCase(unittest.TestCase): body=patch_node_remove_affinity_config) self.eventuallyEqual(lambda: self.k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") + self.eventuallyEqual(lambda: k8s.count_running_pods(), 2, "No 2 pods running") + self.eventuallyEqual(lambda: len(k8s.get_patroni_running_members("acid-minimal-cluster-0")), 2, "Postgres status did not enter running") + # remove node affinity to move replica away from master node nm, new_replica_nodes = k8s.get_cluster_nodes() new_master_node = nm[0] @@ -1219,6 +1243,60 @@ class EndToEndTestCase(unittest.TestCase): k8s.wait_for_pod_start('spilo-role=replica') return True + def list_databases(self, pod_name): + ''' + Get list of databases we might want to iterate over + ''' + k8s = self.k8s + result_set = [] + db_list = [] + db_list_query = "select datname from pg_database" + exec_query = r"psql -tAq -c \"{}\" -d {}" + + try: + q = exec_query.format(db_list_query, "postgres") + q = "su postgres -c \"{}\"".format(q) + print('Get databases: {}'.format(q)) + result = k8s.exec_with_kubectl(pod_name, q) + db_list = clean_list(result.stdout.split(b'\n')) + print('db_list: {}, stdout: {}, stderr {}'.format( + db_list, result.stdout, result.stderr + )) + except Exception as ex: + print('Could not get databases: {}'.format(ex)) + print('Stdout: {}'.format(result.stdout)) + print('Stderr: {}'.format(result.stderr)) + + for db in db_list: + if db in ('template0', 'template1'): + continue + result_set.append(db) + + return result_set + + def query_database(self, pod_name, db_name, query): + ''' + Query database and return result as a list + ''' + k8s = self.k8s + result_set = [] + exec_query = r"psql -tAq -c \"{}\" -d {}" + + try: + q = exec_query.format(query, db_name) + q = "su postgres -c \"{}\"".format(q) + print('Send query: {}'.format(q)) + result = k8s.exec_with_kubectl(pod_name, q) + result_set = clean_list(result.stdout.split(b'\n')) + print('result: {}, stdout: {}, stderr {}'.format( + result_set, result.stdout, result.stderr + )) + except Exception as ex: + print('Error on query execution: {}'.format(ex)) + print('Stdout: {}'.format(result.stdout)) + print('Stderr: {}'.format(result.stderr)) + + return result_set if __name__ == '__main__': unittest.main() diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 16d399865..1055b795d 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -49,7 +49,7 @@ var ( type Config struct { OpConfig config.Config RestConfig *rest.Config - PgTeamMap pgteams.PostgresTeamMap + PgTeamMap *pgteams.PostgresTeamMap InfrastructureRoles map[string]spec.PgUser // inherited from the controller PodServiceAccount *v1.ServiceAccount PodServiceAccountRoleBinding *rbacv1.RoleBinding @@ -1143,8 +1143,8 @@ func (c *Cluster) initHumanUsers() error { var clusterIsOwnedBySuperuserTeam bool superuserTeams := []string{} - if c.OpConfig.EnablePostgresTeamCRDSuperusers { - superuserTeams = c.PgTeamMap.GetAdditionalSuperuserTeams(c.Spec.TeamID, true) + if c.OpConfig.EnablePostgresTeamCRD && c.OpConfig.EnablePostgresTeamCRDSuperusers && c.Config.PgTeamMap != nil { + superuserTeams = c.Config.PgTeamMap.GetAdditionalSuperuserTeams(c.Spec.TeamID, true) } for _, postgresSuperuserTeam := range c.OpConfig.PostgresSuperuserTeams { @@ -1163,12 +1163,14 @@ func (c *Cluster) initHumanUsers() error { } } - additionalTeams := c.PgTeamMap.GetAdditionalTeams(c.Spec.TeamID, true) - for _, additionalTeam := range additionalTeams { - if !(util.SliceContains(superuserTeams, additionalTeam)) { - err := c.initTeamMembers(additionalTeam, false) - if err != nil { - return fmt.Errorf("Cannot initialize members for additional team %q for cluster owned by %q: %v", additionalTeam, c.Spec.TeamID, err) + if c.OpConfig.EnablePostgresTeamCRD && c.Config.PgTeamMap != nil { + additionalTeams := c.Config.PgTeamMap.GetAdditionalTeams(c.Spec.TeamID, true) + for _, additionalTeam := range additionalTeams { + if !(util.SliceContains(superuserTeams, additionalTeam)) { + err := c.initTeamMembers(additionalTeam, false) + if err != nil { + return fmt.Errorf("Cannot initialize members for additional team %q for cluster owned by %q: %v", additionalTeam, c.Spec.TeamID, err) + } } } } diff --git a/pkg/cluster/util.go b/pkg/cluster/util.go index 45045499c..fa8a52a1b 100644 --- a/pkg/cluster/util.go +++ b/pkg/cluster/util.go @@ -238,15 +238,26 @@ func (c *Cluster) getTeamMembers(teamID string) ([]string, error) { return nil, fmt.Errorf("no teamId specified") } - c.logger.Debugf("fetching possible additional team members for team %q", teamID) members := []string{} - additionalMembers := c.PgTeamMap[teamID].AdditionalMembers - for _, member := range additionalMembers { - members = append(members, member) + + if c.OpConfig.EnablePostgresTeamCRD && c.Config.PgTeamMap != nil { + c.logger.Debugf("fetching possible additional team members for team %q", teamID) + additionalMembers := []string{} + + for team, membership := range *c.Config.PgTeamMap { + if team == teamID { + additionalMembers = membership.AdditionalMembers + c.logger.Debugf("found %d additional members for team %q", len(members), teamID) + } + } + + for _, member := range additionalMembers { + members = append(members, member) + } } if !c.OpConfig.EnableTeamsAPI { - c.logger.Debugf("team API is disabled, only returning %d members for team %q", len(members), teamID) + c.logger.Debugf("team API is disabled") return members, nil } diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 0c29275e6..f992ff782 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -329,10 +329,9 @@ func (c *Controller) initController() { c.initSharedInformers() + c.pgTeamMap = teams.PostgresTeamMap{} if c.opConfig.EnablePostgresTeamCRD { c.loadPostgresTeams() - } else { - c.pgTeamMap = teams.PostgresTeamMap{} } if c.opConfig.DebugLogging { diff --git a/pkg/controller/util.go b/pkg/controller/util.go index 815bc7b74..8aa891c09 100644 --- a/pkg/controller/util.go +++ b/pkg/controller/util.go @@ -15,7 +15,6 @@ import ( acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" "github.com/zalando/postgres-operator/pkg/cluster" "github.com/zalando/postgres-operator/pkg/spec" - "github.com/zalando/postgres-operator/pkg/teams" "github.com/zalando/postgres-operator/pkg/util" "github.com/zalando/postgres-operator/pkg/util/config" "github.com/zalando/postgres-operator/pkg/util/k8sutil" @@ -31,7 +30,7 @@ func (c *Controller) makeClusterConfig() cluster.Config { return cluster.Config{ RestConfig: c.config.RestConfig, OpConfig: config.Copy(c.opConfig), - PgTeamMap: c.pgTeamMap, + PgTeamMap: &c.pgTeamMap, InfrastructureRoles: infrastructureRoles, PodServiceAccount: c.PodServiceAccount, } @@ -395,9 +394,6 @@ func (c *Controller) getInfrastructureRole( } func (c *Controller) loadPostgresTeams() { - // reset team map - c.pgTeamMap = teams.PostgresTeamMap{} - pgTeams, err := c.KubeClient.PostgresTeamsGetter.PostgresTeams(c.opConfig.WatchedNamespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { c.logger.Errorf("could not list postgres team objects: %v", err) diff --git a/pkg/teams/postgres_team.go b/pkg/teams/postgres_team.go index 7fb725765..6e9a825e5 100644 --- a/pkg/teams/postgres_team.go +++ b/pkg/teams/postgres_team.go @@ -94,6 +94,9 @@ func (ptm *PostgresTeamMap) GetAdditionalSuperuserTeams(team string, transitive // Load function to import data from PostgresTeam CRD func (ptm *PostgresTeamMap) Load(pgTeams *acidv1.PostgresTeamList) { + // reset the team map + *ptm = make(PostgresTeamMap, 0) + superuserTeamSet := teamHashSet{} teamSet := teamHashSet{} teamMemberSet := teamHashSet{} diff --git a/pkg/teams/postgres_team_test.go b/pkg/teams/postgres_team_test.go index f8c3a21d8..f138ec124 100644 --- a/pkg/teams/postgres_team_test.go +++ b/pkg/teams/postgres_team_test.go @@ -46,9 +46,36 @@ var ( }, }, } + pgTeamMap = PostgresTeamMap{ + "teamA": { + AdditionalSuperuserTeams: []string{"teamB", "team24x7"}, + AdditionalTeams: []string{"teamC"}, + AdditionalMembers: []string{}, + }, + "teamB": { + AdditionalSuperuserTeams: []string{"teamA", "teamC", "team24x7"}, + AdditionalTeams: []string{}, + AdditionalMembers: []string{"drno"}, + }, + "teamC": { + AdditionalSuperuserTeams: []string{"team24x7"}, + AdditionalTeams: []string{"teamA", "teamB", "acid"}, + AdditionalMembers: []string{}, + }, + "team24x7": { + AdditionalSuperuserTeams: []string{}, + AdditionalTeams: []string{}, + AdditionalMembers: []string{"optimusprime"}, + }, + "acid": { + AdditionalSuperuserTeams: []string{}, + AdditionalTeams: []string{}, + AdditionalMembers: []string{"batman"}, + }, + } ) -// PostgresTeamMap is the operator's internal representation of all PostgresTeam CRDs +// TestLoadingPostgresTeamCRD PostgresTeamMap is the operator's internal representation of all PostgresTeam CRDs func TestLoadingPostgresTeamCRD(t *testing.T) { tests := []struct { name string @@ -59,33 +86,7 @@ func TestLoadingPostgresTeamCRD(t *testing.T) { { "Check that CRD is imported correctly into the internal format", pgTeamList, - PostgresTeamMap{ - "teamA": { - AdditionalSuperuserTeams: []string{"teamB", "team24x7"}, - AdditionalTeams: []string{"teamC"}, - AdditionalMembers: []string{}, - }, - "teamB": { - AdditionalSuperuserTeams: []string{"teamA", "teamC", "team24x7"}, - AdditionalTeams: []string{}, - AdditionalMembers: []string{"drno"}, - }, - "teamC": { - AdditionalSuperuserTeams: []string{"team24x7"}, - AdditionalTeams: []string{"teamA", "teamB", "acid"}, - AdditionalMembers: []string{}, - }, - "team24x7": { - AdditionalSuperuserTeams: []string{}, - AdditionalTeams: []string{}, - AdditionalMembers: []string{"optimusprime"}, - }, - "acid": { - AdditionalSuperuserTeams: []string{}, - AdditionalTeams: []string{}, - AdditionalMembers: []string{"batman"}, - }, - }, + pgTeamMap, "Mismatch between PostgresTeam CRD and internal map", }, } From cee4bf82c7960f69d25de4099332b61a75579fd9 Mon Sep 17 00:00:00 2001 From: georgebarbarosie Date: Thu, 18 Feb 2021 07:21:26 +0000 Subject: [PATCH 25/26] small fix for postgresql CRD (#1368) --- pkg/apis/acid.zalan.do/v1/crds.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index 3c4bc315a..19430e78d 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -604,7 +604,7 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ Items: &apiextv1.JSONSchemaPropsOrArray{ Schema: &apiextv1.JSONSchemaProps{ Type: "object", - Required: []string{"preference, weight"}, + Required: []string{"preference", "weight"}, Properties: map[string]apiextv1.JSONSchemaProps{ "preference": { Type: "object", From 3962e71ddd897e9aaa28c9b00e5e17e0d8602ead Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Thu, 18 Feb 2021 13:38:27 +0100 Subject: [PATCH 26/26] bump to v1.6.1 (#1367) * bump tp v1.6.1 * update UI chart * improve docs and manifest examples * use Spilo 2.0-r4 and update docs * minor updates to admin docs --- .../postgres-operator-issue-template.md | 2 +- README.md | 6 +- charts/postgres-operator-ui/Chart.yaml | 4 +- charts/postgres-operator-ui/index.yaml | 20 +- .../postgres-operator-ui-1.6.0.tgz | Bin 3878 -> 0 bytes .../postgres-operator-ui-1.6.1.tgz | Bin 0 -> 3877 bytes charts/postgres-operator-ui/values.yaml | 2 +- charts/postgres-operator/Chart.yaml | 4 +- .../crds/operatorconfigurations.yaml | 6 +- charts/postgres-operator/index.yaml | 20 +- .../postgres-operator-1.6.0.tgz | Bin 19074 -> 0 bytes .../postgres-operator-1.6.1.tgz | Bin 0 -> 19296 bytes charts/postgres-operator/values-crd.yaml | 8 +- charts/postgres-operator/values.yaml | 8 +- docs/administrator.md | 311 ++++++++++++------ docs/reference/operator_parameters.md | 2 +- docs/user.md | 36 +- manifests/complete-postgres-manifest.yaml | 30 +- manifests/configmap.yaml | 8 +- manifests/minimal-fake-pooler-deployment.yaml | 2 +- manifests/operatorconfiguration.crd.yaml | 6 +- manifests/postgres-operator.yaml | 2 +- ...gresql-operator-default-configuration.yaml | 7 +- pkg/controller/operator_config.go | 4 +- pkg/util/config/config.go | 4 +- 25 files changed, 318 insertions(+), 174 deletions(-) delete mode 100644 charts/postgres-operator-ui/postgres-operator-ui-1.6.0.tgz create mode 100644 charts/postgres-operator-ui/postgres-operator-ui-1.6.1.tgz delete mode 100644 charts/postgres-operator/postgres-operator-1.6.0.tgz create mode 100644 charts/postgres-operator/postgres-operator-1.6.1.tgz diff --git a/.github/ISSUE_TEMPLATE/postgres-operator-issue-template.md b/.github/ISSUE_TEMPLATE/postgres-operator-issue-template.md index a4dec9409..b96eba1c6 100644 --- a/.github/ISSUE_TEMPLATE/postgres-operator-issue-template.md +++ b/.github/ISSUE_TEMPLATE/postgres-operator-issue-template.md @@ -9,7 +9,7 @@ assignees: '' Please, answer some short questions which should help us to understand your problem / question better? -- **Which image of the operator are you using?** e.g. registry.opensource.zalan.do/acid/postgres-operator:v1.6.0 +- **Which image of the operator are you using?** e.g. registry.opensource.zalan.do/acid/postgres-operator:v1.6.1 - **Where do you run it - cloud or metal? Kubernetes or OpenShift?** [AWS K8s | GCP ... | Bare Metal K8s] - **Are you running Postgres Operator in production?** [yes | no] - **Type of issue?** [Bug report, question, feature request, etc.] diff --git a/README.md b/README.md index 7edb60d84..b29142967 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The Postgres Operator delivers an easy to run highly-available [PostgreSQL](https://www.postgresql.org/) -clusters on Kubernetes (K8s) powered by [Patroni](https://github.com/zalando/spilo). +clusters on Kubernetes (K8s) powered by [Patroni](https://github.com/zalando/patroni). It is configured only through Postgres manifests (CRDs) to ease integration into automated CI/CD pipelines with no access to Kubernetes API directly, promoting infrastructure as code vs manual operations. @@ -24,7 +24,7 @@ pipelines with no access to Kubernetes API directly, promoting infrastructure as * Support for custom TLS certificates * UI to create and edit Postgres cluster manifests * Works well on Amazon AWS, Google Cloud, OpenShift and locally on Kind -* Base support for AWS EBS gp3 migration (iops, throughput pending) +* Support for AWS EBS gp3 migration ### PostgreSQL features @@ -65,7 +65,7 @@ We introduce the major version into the backup path to smoothen the [major versi The new operator configuration can set a compatibility flag *enable_spilo_wal_path_compat* to make Spilo look for wal segments in the current path but also old format paths. This comes at potential performance costs and should be disabled after a few days. -The new Spilo 13 image is: `registry.opensource.zalan.do/acid/spilo-13:2.0-p2` +The newest Spilo 13 image is: `registry.opensource.zalan.do/acid/spilo-13:2.0-p4` The last Spilo 12 image is: `registry.opensource.zalan.do/acid/spilo-12:1.6-p5` diff --git a/charts/postgres-operator-ui/Chart.yaml b/charts/postgres-operator-ui/Chart.yaml index 9be6c84dd..8ff7f6637 100644 --- a/charts/postgres-operator-ui/Chart.yaml +++ b/charts/postgres-operator-ui/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v1 name: postgres-operator-ui -version: 1.6.0 -appVersion: 1.6.0 +version: 1.6.1 +appVersion: 1.6.1 home: https://github.com/zalando/postgres-operator description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience keywords: diff --git a/charts/postgres-operator-ui/index.yaml b/charts/postgres-operator-ui/index.yaml index 948a52274..7706f5bf8 100644 --- a/charts/postgres-operator-ui/index.yaml +++ b/charts/postgres-operator-ui/index.yaml @@ -2,11 +2,10 @@ apiVersion: v1 entries: postgres-operator-ui: - apiVersion: v1 - appVersion: 1.6.0 - created: "2020-12-18T14:19:25.464717041+01:00" - description: Postgres Operator UI provides a graphical interface for a convenient - database-as-a-service user experience - digest: d7813a235dd1015377c38fd5a14e7679a411c7340a25cfcf5f5294405f9a2eb2 + appVersion: 1.6.1 + created: "2021-02-16T12:16:51.963793476+01:00" + description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience + digest: 3d321352f2f1e7bb7450aa8876e3d818aa9f9da9bd4250507386f0490f2c1969 home: https://github.com/zalando/postgres-operator keywords: - postgres @@ -22,13 +21,12 @@ entries: sources: - https://github.com/zalando/postgres-operator urls: - - postgres-operator-ui-1.6.0.tgz - version: 1.6.0 + - postgres-operator-ui-1.6.1.tgz + version: 1.6.1 - apiVersion: v1 appVersion: 1.5.0 - created: "2020-12-18T14:19:25.464015993+01:00" - description: Postgres Operator UI provides a graphical interface for a convenient - database-as-a-service user experience + created: "2021-02-16T12:16:51.96319758+01:00" + description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience digest: c91ea39e6d51d57f4048fb1b6ec53b40823f2690eb88e4e4f1a036367b9fdd61 home: https://github.com/zalando/postgres-operator keywords: @@ -47,4 +45,4 @@ entries: urls: - postgres-operator-ui-1.5.0.tgz version: 1.5.0 -generated: "2020-12-18T14:19:25.463104102+01:00" +generated: "2021-02-16T12:16:51.962463462+01:00" diff --git a/charts/postgres-operator-ui/postgres-operator-ui-1.6.0.tgz b/charts/postgres-operator-ui/postgres-operator-ui-1.6.0.tgz deleted file mode 100644 index 68a43b51bbf24a28d30963679e0dd8edddaffded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3878 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 diff --git a/charts/postgres-operator-ui/postgres-operator-ui-1.6.1.tgz b/charts/postgres-operator-ui/postgres-operator-ui-1.6.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..c59d20b2f1fe34400f2b4b338a9096373a1d70ea GIT binary patch literal 3877 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 literal 0 HcmV?d00001 diff --git a/charts/postgres-operator-ui/values.yaml b/charts/postgres-operator-ui/values.yaml index 2aef84f1c..926d99b39 100644 --- a/charts/postgres-operator-ui/values.yaml +++ b/charts/postgres-operator-ui/values.yaml @@ -8,7 +8,7 @@ replicaCount: 1 image: registry: registry.opensource.zalan.do repository: acid/postgres-operator-ui - tag: v1.6.0 + tag: v1.6.1 pullPolicy: "IfNotPresent" # Optionally specify an array of imagePullSecrets. diff --git a/charts/postgres-operator/Chart.yaml b/charts/postgres-operator/Chart.yaml index e5a66b6e3..857967a48 100644 --- a/charts/postgres-operator/Chart.yaml +++ b/charts/postgres-operator/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v1 name: postgres-operator -version: 1.6.0 -appVersion: 1.6.0 +version: 1.6.1 +appVersion: 1.6.1 home: https://github.com/zalando/postgres-operator description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes keywords: diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index ef9b2c84d..3906f9052 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -65,7 +65,7 @@ spec: properties: docker_image: type: string - default: "registry.opensource.zalan.do/acid/spilo-13:2.0-p2" + default: "registry.opensource.zalan.do/acid/spilo-13:2.0-p4" enable_crd_validation: type: boolean default: true @@ -382,7 +382,7 @@ spec: properties: logical_backup_docker_image: type: string - default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.0" + default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.1" logical_backup_google_application_credentials: type: string logical_backup_job_prefix: @@ -511,7 +511,7 @@ spec: default: "pooler" connection_pooler_image: type: string - default: "registry.opensource.zalan.do/acid/pgbouncer:master-12" + default: "registry.opensource.zalan.do/acid/pgbouncer:master-14" connection_pooler_max_db_connections: type: integer default: 60 diff --git a/charts/postgres-operator/index.yaml b/charts/postgres-operator/index.yaml index 6b64fd705..a0f705ec9 100644 --- a/charts/postgres-operator/index.yaml +++ b/charts/postgres-operator/index.yaml @@ -2,11 +2,10 @@ apiVersion: v1 entries: postgres-operator: - apiVersion: v1 - appVersion: 1.6.0 - created: "2020-12-17T16:16:25.639708821+01:00" - description: Postgres Operator creates and manages PostgreSQL clusters running - in Kubernetes - digest: 2f5f527bae0a22b02f2f7b1e2352665cecf489a990e18212444fa34450b97604 + appVersion: 1.6.1 + created: "2021-02-16T11:49:43.295433402+01:00" + description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes + digest: ce9cfc0d4838edf307b690b942bd4e1ea73c3b93bb5552ae8ecd2952d55383ea home: https://github.com/zalando/postgres-operator keywords: - postgres @@ -21,13 +20,12 @@ entries: sources: - https://github.com/zalando/postgres-operator urls: - - postgres-operator-1.6.0.tgz - version: 1.6.0 + - postgres-operator-1.6.1.tgz + version: 1.6.1 - apiVersion: v1 appVersion: 1.5.0 - created: "2020-12-17T16:16:25.637262877+01:00" - description: Postgres Operator creates and manages PostgreSQL clusters running - in Kubernetes + created: "2021-02-16T11:49:43.292890391+01:00" + description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes digest: 198351d5db52e65cdf383d6f3e1745d91ac1e2a01121f8476f8b1be728b09531 home: https://github.com/zalando/postgres-operator keywords: @@ -45,4 +43,4 @@ entries: urls: - postgres-operator-1.5.0.tgz version: 1.5.0 -generated: "2020-12-17T16:16:25.635647131+01:00" +generated: "2021-02-16T11:49:43.291315248+01:00" diff --git a/charts/postgres-operator/postgres-operator-1.6.0.tgz b/charts/postgres-operator/postgres-operator-1.6.0.tgz deleted file mode 100644 index bf98cd8183d93920720fcfca1bfee716dabe6960..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19074 zcmZ^~Q*idik1d~sv6VI0#iy_92FD#$)HTop>t(`omSXF7%EhYWV|%wJK2K(CtK@}c>E+tS z)2_dSgs?2S7Fbf@hnvp3BNIeio~TsA#m}|Rv`cei^fVl>!2T&crm^4!jBzC*2a0ll z!?T-I@zu0>#>Z()j!!R8!0Qe33wZsE4FU@M;C)}z1FbaOv4t5JX!pP?$<$Q%d zTu1mR%jdHt`e-x;ui%1&ASaM`xXSstu)S}X+(o8B?v8eG9%9q=5 zudd|UasY)oWD8p;Z29VRE~(#}9EXoqghwn^;lke6;Ur%9i2jg7{2VJgVl{#PLoYVM z1OA6gUX-$!cQMIS<{M&)LJp$rr%br8_=T_LW_Ox1?08xJ4QQ_t`Kwt5a~aZ&(_*S> zd*hk^Yx3S#JTaiW6BDfR81%LHX)2F>1nS?hyI}%d@9$D)*Xf6%j#Frva}lQWdi;$# z0f%@t0EcqSZv&K2MZ0bGEd`lzGv7hFWyEz!Bsj+3nDLWsE#7M8&yp+BEpEw~hGzNO z}GC!fn{M}T2=J3&;2LcA{~Sf>1{E-D8735C32KB1C9AaR9(xejy|)M2pg6#^S~&Xi95*=^<)#qSEm@kAc>uqeZd&}iee+b(XZoD zfoqTq1_49>GO>ix_wk=u$=9JpmB#%Ye$d2d@#K!*1&hl~_DTMjG$9%NF&kJ+8qTsv znUbWFDU|&~oiOwvj*8V1*w`9m%*s-j za3f$^EqoiV%h*Nr~a8p~vxu^c!Q8894C%1+|8SJoc|^x!G+M z%tH(WBBM3BtUv1K-$-NG^4GGAE;5Fc7SWWW4oDbyh<2%4r-Vhtm)OXurGv9ne=e~h znUYW=0^R#=D@jOkwY3#-Xwk#jN;6{7O_s;0ahScQ)x;TOW8?b?sxF>ly^ZV+^Zk9g zOC-%`LSd`6du4vr>o-S<^_faZPnI71z&;{yPe1aIgCE9xy=`xx<>cb(xxi84jufX7ChFb;DLIUv%85uR==L+oGoE^RN$4fqpDNJ?EN#{drxYe)J1bQK5l%7p(@?#!3pguiptMqUvd8 zqymUNa^9&JOJ_6AJC->YuhPo<QGws!3MV7O}^5;5q2V@^JRIl@=aHAfG!kS(M(Fks7A zPQl0$4PGEYazqPVQWfe@wUP_fLztsfwc;NDl1|R6TE!GvxRq2$JS16YDImfWvF#g{ zu=#hC;i%bAxWsc5rZY|RUgW=G>M$45?Tz+zwey+qm>J8{8-~PG>$fCN!AJ`ZBy)Tm zJv%ap$x$*{7*a2wD@%p|dT1alEsB2;Gw*RLqRFOdeGjY9%5$H{QG#;qZ6s?~-kK`g zS8!*SFpfvVC5|WM03@s(M$#&=scF$4m3XL8_p%QQMUD^UFOlZ7qUDTMl%LuDQD{q=WLJ;%vCGF}JwNCFLgqy#qlgJQ`A ziNT0Ksgyqu*fTz(!vxjQi!I4I2gy8CvtZ&Hkcvu_K&%k%Leg2QS5#4 zO5wHq3X9P8dnh=##BV13T^j`?^wkUp@##(x<2bQt>-0#yqkzQtP#f<2Y~$_Ka>QiV zXp%qQ>4U(pzb_ZV|Df&!@p{~^+%8&>u}Z%~#QIK5%9=NxHCJz5oa1mvR&%-A;Px|~%^$Ayt(emk7DiA}6 zPm$l2rJne~JQ zoD}T2w?VRMG74IxXcmt?{k|o^MHq%Jv|s)>SH&5!NAj>@_zcX3meXkCAwkhg7zwil zl%i3i(A>)?^*&~H$kVP`XjyQsvd(PA6AaKP-r2)OSZ#2*^;PIeBU&LE_G&$N30JP# zrL8*}l8HqXg;9SlKMLk3?6#Gj+6*&0IwILOI~~z<>l{SJ^mzC|aNaaneo|>kZ|0#t z7dfKt3Y;X>Y*?7+aF#39ek4_Mk_GlS=cs|kqQe?=Fr-(6dO;!YbuGj-S7G39baT|n z%uQT}IP#H6FN*!EnlcoQO2?@wKhBZwx$Up}TJZWb0$M}0uEV<_M4U>Mq_N`Zz}HNy zaN|94U@arLe0%5xs;HY+6jS0YCz>4-85sTAIP$`AHPaD&aWco0s+(5*t=(vy8XNjL zjEo93*M6@w$L+=f>UbArX3Q2&#tPTNY^wn`Tw;kobhDPWgm?4`Zhypct%@|%rY!j| zk&9+zGL)rF2|}v1?e2inQUk9mxeqnKyel>Hpu$V&I)oDkqfTRIm8l7P0tcsSEjf!4PnrQ<=F(NUO5&u`I1JS!X*UO z;+e6@5Y7Dp^`)|B^?RR23bfqG4%@qcjo%8lo+?R;v5LNUWlY`k&ZbmY%1Bg1mcjK) zgLtHn-ehQtSMdZPDcTl!X1x(^>B`$g{z~GbiRT@_lX*sIE8#=B7}AH0HC+7(<+;W&?v7cJjeaZ>U?8%ocE^@j4b2WD*sjYDCV42UwB zA*-MspVR|0jd_m2ROKeF(@i8+;x1fM%A4_xm;gyJ^aa?C<}NnQa zcTX46P+uhIi;v%9==a|yBB)VhXof6k1_?}vuUZb* zpZTKD3qwfd@<_{w-O(W?I@9EM_s_){JM3FmWDI?uB2mIstYljr2mu|FkcAOxWZ?Qg zHd(csf$ZpQJmE^NI8BvIK>;zuv39{<@zdj{;|}D_wyFm=5z`_Bs`_mFjDQ>T|SNDr|0rzEc?dJGsG4l5ovdv#){u!r|xlaBp|D3wyMNSr7D*n#+oF|L;CTlFedm2I3cnE`@0yiC>3dn>?c^` z;tnz>;nEjy8Z9P_B0{c27i2a*CnSpWN;85lKa|_eRW*%i;>5{A1d-+6EuHtdz-_|F zMzPDV1A)NUzP=J6H!jvQtc<hd%^uypmWl6o1PVzZ-r$GNJ+eoR}=~d8=EQ59{vt5q~4*2?;@*bSvxe1%N$Tn#uW`g_Y!}1;)+;J}` z`Qig%2R_O_!dPeJ#TN0AZTmfhnX|TN5}INHt19VNT(&iIpVJ1L@$9{@;dcdDZ9`WY zDtNUv^6RubYIK@5vIOmR(<~YAY}T;l8^qY0KXH|-3p!y3AGG7b(=M;tepmUK*bA~w z2eRl?!h?Ojtf4;4jKOs7I;OJWXe&ebXdA3vD)s)2`*`al-l+~tk38Lo0Bc-=N(>ma zT500{ZASw&m)?6D7ZG;|&Ok4gz~t_+z<*ziHEq8sDlA3E$nTF;J_wdO#gZ#_U`Ob4 z_kf<{wtz&VM;E!vso-Jd-9?U!X!@lpgi&Ze9CXChl)v&COzcEei-f#LASO;%Fw!*m zyVfEQKQ_lcWwp=z_lkBFx9UOsSjaNt2r?{Ej7E1~5`iU-otzx1_200IG1km}L9v?gs z1|$qpLjo!md==o0nyff2)e+MHn#0}($)(E)DiMYfU*WNF>X{w6Z~jb&KFGv_ep+5Eu9 zH3!JH%=8#A$Pg8Hg%nZW2ucyUKC6$=a(YKz(v7uU1D+w0_l064|L znHcGKh>Z#OSeg^Fv*L})yX~LkQjyY8c29tGnry{d_DQ5y(bZn7)sTE*BDUk&A}WXP z{$L_T7BgpklQoOPsHqp*5E%XPyd`^|QBwifYk3)dGDK~ZepEUy@tG6@wJfQMewW)( zB^AFc$Z&XzIoizMHT1mmkJ=w^?~kAIL#KnH&00Mv5wz>5>3N`y2b?5BBeRGV#rK2C z?^Xv)mfG$+qVe1Jk$-xWqGaMtY+I&K{}lbZst3SIIOoce-f0fx+DU4FlBRREfFF+H zHVxgeoIHAWqda3TgTA)&Ky_ch(fi~TP_oHYAi7>MSOytY@f4%| z<;;q{n#gH+ZGdn}kcstijigNnX}ZPjwRUki!%g#`(uQ4kZty(9P2gr+!o1qw0Jc_J zc2VnUb;@q?c{vnfS?bKU1(Tkv2E=D6CKO``F|OKWMjl^WCz|hS&kK<%=9d<~t`$(O zc5o)>DB>thqEP|1OhktL3XHX}I!zF6LOoN6m?bFO=#(#=<;4nVivAC`FAR zxa$yqZ12+KA+c!+mFnZn^+=kp8FBSxUCcj1(w;=hjuP6!YhyyzBo!6Q8cyI$*fEZ* zd(fy;)Y#FQQKybNyPE49f>qIkP8|aJT7NLQqX*4be@-uTEE$6w8XE&MJ7NjcgaLYF zaMMKVaVmLcQ#22Ux~$bqdN6At@BIdNCCls-Z*UsXwanoW*>%G+okgowwU-bCcA}kq zl(iP(^K*f(tu1@2lWrpbj7=EKgx$ntytxy#BFEeaBEmd}Gi}#r!A80e!J_vM4`4OV zBADlIm_w5fMZNz-{AKJgyKKZ1SUZ$tq&Khr`Xu>MUWSN{s7zB+epxLG27NfHp!u`& zjJ!@6!7ChPFCSc#Fd}ZfWoB~_#yuw+i+8dKMx&L@=AWJnEntG;A#+-T_Tv=Hlh|%_b4Y4A+v<;oN3uPkj0J(m9e}4>&q-rGXqM&1 z#ioz_-8Zm%Fc1m^+}SxD`~r6K>W+b)zr7yzBe`MQ2*%eTa1a=XXR4;H+yDL6bP?Tc zd|df$aRQOYA4*4e*;b%UCt#%I=Uyn*i8L?mVXx!c<{e9&^DSXu@e9Z_G%)nN_v)~I z8|JANsux0s{Se63+(x8i0K_s+d8#z3z{Yq6YK?W;Xu_^qbF+m}IiQ7JP3gm$A`dor zF0VXk8%A>#wMMTof6{(QE*7ov$@8P-4AU(d*(#g2RhkSo=-54(U}-J?MT&fHXXdQh zyQ{K}>Ywas(#IczZ{zY}4Bsy4Hc}k5QuAWQ?^kHv(ZBry1Q^j%%cvufoMmFyh|^H z+^Gi6t*NS?c@-j0jnEE408IJ~5^v>^?_o=CHl`XY2<6Rl7O>y@_Kxxf>gMecm%rCi z-p)!q^I_4g1=&{S+nO%?+jItL+?#L*j7=sEL;8&Hm3}R*==5$Y&)O`G-3?%6{wl(C z_d6z6ZmqR35kh|#WD25DI5#Rw$8{r#`e=WiSy=EC!U|mK--0R?eP%w5mlu^i-R{q) zS%42Fgm<(oijKF+bo#Gp`)5 zhh`GB>t=Y85jd8y5f1kYY`X}*hl?8pNYL%x9`#WYQ^J9^i<*9t7fY*0+81X<;SvcFhWZ-SDnL!gavicfWw|`R0o0A=mm5-%-}Brq zw*EfQwAN^v6GCR(qgq$J7bx@uyjC{`HCys=4%XX%j@K6Z_g;bBrt*Xr|F+6y`bpCi zm>6$@pFKa-*O4{GkU8<3s`1xgcl9gHJVlyv#$Q5s7$6r%T2(byJ=`ObYb;c6fO?r{ zEqKb(lh4{VDmZS{*d)LxLfZzO$0h5|wW)18(@UDz@uwfP7b(4-_J=Mguea{&`Wm12#rOJf?RVTe zZFhG~kSPY^H>Uq`=+T2W-&e`{vzKrl%i;5B4*^(sUY+U_A$_(_i&RB?Xp@c3cU-!Ancfd2*R%CEBS`hYr zFU-I45aky5e8(pKpsxQ&NiYv*Xh{1gM}0za;WzJP;@u^dz|MF_RKOmm(hy;5A*N6UWffVs+EdACYWW zIIpiS2}4>Ha<&7H3?JCz*AL=^2Mix8-Dz?z)4rRz7Aco1eizBrae@W++Va}R+1DPV z9)DkJN*BBCw?G?f!~%-rV)D3r!34I$3G!JdHodh3P>##_@; zV%Yj~mFIF))h*(1qaUl2jM5@j0mmlT=3`n<5Uy4&?wt!>@@)$OEvfF&N#1>9OhA z@Q45urgRL9=ww$m4j@_P3i6~r1to0w8jiquT3bc_)PKEZg2*C?#soG|cMDrEs7b(u z0TgxYMP&v84#vw4`NKArzniU7l~uAp(%4LS4zgq|LD3G7O}DULV-Fk>*G2*%32I4z zU)6^p^(;UomPd8ru)b}&2COq$Um;;1wmHJ+H-7zg&{FG@LCSC^ZUsXZc(Ao*H9I%( zhVJL14O?{?TNIOiL--UY@4k7whihSqWQg9pZ5x?8`8@Tkuny@!ylYdRJxAoyH#W)v zkE@hNS6*YOMYd5KzvsPm4-(V0`Pb9g_tfSU+%5y&{yi;k2~?hXj%O4J(CjNSDS(EcGl?l5s^4NgecuWWUDboCp-bM{G_C2Ws5 zvJBC?eVtnZDItT-EZo|`Q`S_CMT1$9`qb-GQ-v&iH%NR<5O#%5TS!9M64sqiDUo%I z973C$s-aRw%M@G(eI@KpV~lorJFJ(RE!@ZZcL(%6)L57wt9~tZv66Jj|?t3c<@O zlCqz}2D!aov>WY~{?S~gVKJ`nTX%tSa?wldU`upkcspivp zOx#3@E`$5(4kMf&54X!ZL(U~68BFcwwd~SX4N`Qrf}zSUZX?cZUTL*(N*fgt%VjA9 z90yp_mG@$;qAN|Pj60PHO(AK;j|i>x-rzlWY`l2V6-{&`+7bY%cqZk@$?XtYRj{oD z&J{CEBi1KvV&)8dn8#7$B1UhP>ENja_u-5Ue{zS4rRF$$&+@;KKlrhjFO50W%d3|c zXaa1&MlDyX^>J$25q`Qrr%@QR9pZztJ#1kK%DQLX*+Kk#RQgs4)+~*fBb$DZVciAq zoBmitV%Tl)XiOzRZ6+vwRBA9H>^Zl;>@m09P%U-wXQi$y%b(fR?`I=c1EyhUMdATI&CfzEGw;s1rGUY4@crG-7W99UAV=EEV# zDbsD3>Ju#5?S(A``e?Ywr^|Uv6fi{k8t?QxCTsTEeBh_>IIQCaY54agat(+7XqtpN zan|YU&*qzTxjE|%d6VKcQd;;=AhaIdZX}+>UuTt8@gC|49xSwfppPt?$ghp1)8~1+ zX`=~NLu5I!Xtm1L+mMr#?wBH_=idZ1I;XaNXNC9oURTL1_1KaCR?-jjzwc#^?!%2Q ztRDfgpR>_R{*}4_9A)SOnt}CAYj&dV{B{Ub`x}8}HKs2HDaM2NBD&&X4e=V}+@|vp zwFbO8l!}^QN^l%KJq&@W*+crtZyzQ2TP}Vt;?)|~Yik5Zgm_BD9IO#jd? zdsk`Kzs}2-t}OaCEowuq5jFRXoUN-w3z*KwV|L|uliU#GU;4n08o&{oMnqyGZd+?D zV6DZVP`hY>>7~RaK^(PwVDBby z%%-+uw2;74evwzdTY^mvt}|GVPu-F`d-Jd+c&o9;Fspil^*UOsM6!$=Ki2(0tQ(CZ z&pEi`qr)fni#6jhSzNf?iZ#LAK3WP{rKo!Gy>4vyU?CDUX` z6E4!ihUeIXCc>%{x}`6muT}GT)nv8I?WS1qIZ0+9`i(dsxl435Im^Y7D*O(Qp z^mF`qFiCzH&)u~iyfcVN=Jb6|ZDu3=mEcII7idex9DX-<{#@9Yq!UY-t<9FUkED;fg#VsL0S%! zR~Ld+1g3Eg;u*dVm4EypC zxTK4%!}s;_aIaD5-7Ej*eV6@e8qZ_R(Pcu?>I4@PA!(Ml?XBOvRgBzNbwgg~o({?Y zxBV-b;)7etJ7}F(-$%5}NEl?2Jy4>rPiEVzYA51F40*9FtGIHa>(?OaO1P@=^Drb# z!-I_zf7J)RBF3!nuSJD(O-N@aFCGGr8yGAY(XAa;#6$=(F{bZ&@yF!-$7qm!>Zca} zOyzV#n(3}P`8iI!?@l*37mmvay8`ko{HPwUR0jHG+YDD zoqPlF`eidy2zKq5{zcFdo-7?>7()95v>suF=Cg&wxvs27mn|uP{7?&G!u}LlQL|{% zf|TDii=Ed$cD-Nc@5UuC>!gD=2>bO;?R;7Nsl5qD3hUnN-VcxJ?4h(rK86FDF%=^s z#p!2L<`PUIzHyzqWGrK9+h9|`!413pJ+*82lUnmrNR!mTmUN)!cBkwwr0=EJQ=W0W zb?KX?Hiu?m+%m@@o|a@Pt|2R*bBd&;S~ExeoW=GY%rzr(~YdRG5dF{1^ z?{$qT$zFaePuZWwBu^;UGK%$;#@CfHYtw3i*PlgBS)s*&zj!O_ZgbE4((6jwhHPwP0WUdTaUaA1!~ zXomemMn|f;Ls5jD5x!~?iEdwtcK++*Az{|$fXt4^`Wkemrr&?=OlB=aE3gm6qVqWO zn5|_oXtY`>5q6iTIuj8CjhBC=CE;;gx5XtGXOy`E)=sTLdJIlkf?D$Ze|H^o4~Br; zPkMD`L>8Y9BN^k)P;Ix%!p*#{hz55veuRD%AJV?nR->T#G&bExyX`qz7v3t$O6)9N zc~_*sW6E+)jWk<#RR4uzwu5f=3RwL$_(~6~e@*?;y3KW7V^lfpQnMUMZn8!Kw+-jg zNjx(7^f?eWmtD5fv=OWUu2o8ErxO~VUs%4B88jJ}E|Q_G(2YQA%~^?&bTP)q)OZ_q z9HG2CoD;o#Jp=dT1A%-0?w-9*fu%>Y-GRFA{r%UmzUN!E`P!Ohvt3)DX2Oflo{Q+P zgpov8+IIb9HCO;9V{IeH_Ha75=_s+Wfzt04A11o!d@h?7+jS&lxeSAO8c|PAs?-6uy zkG4Udw>M~Y99@;4x2JWWmw8*h$V1y$g3q^=yz(B^?rG*$k!@L=c&mZ!W4Baj#k>tX zdR8WH;Tudycc-@Cn+7SCV68@aiJJCF0~ ztdi~wtkB(YiuK`+O-pclfW9U8YKhrb7k@ggicYCvwNfmHBoPck5qr}{k0;>T#hO_@ z3A>Wtwl9^uhn_R%rhmi>N5Q5MBrN6Q@%L;6R8$mZNM-g-Dcaixg|7nB?WFb z?yXcFKV&pPc0v*(NKzAxB)uSP&SF4j@<*6F5^h%T*1yleVfbif(p)gT*E5n{rx~-B z2)nQwn{m|^V!rBzBnpAI&I3D7XCE#Jn>Mzx`r8e3ftt=gG)B#F#yb$O1(-Ty`*e@w zApkVK+F)A0UdN+tvsouY90SYg!)Gf~t4)hlq@p%*fwZKKi$%u8Vt%Kyr|iP+z>#BPE(QzpjkN`#( z_R994vp8l`&``I!IyK|1z&TBkUd*M{|J;ORxUkl@j|hzcAC!|tK`w2>)4@wd@# z+MVcBi>zU){J^PMam}sqOqoQdE!yFuiCY8y3veAi~_!y z!^SaK-WpuW>_$wp#BasJ*vaYs`ymOxM)Km3^m&SP`5#UNq;;YkO}|m-?TwM{>}0S_ zhK+3Q22*LCV!+l!O(y%Lsm&a$*YeN6o@;i35XN49?bk=W!<9iSU6^P%q|MP0HMQq@ z=CBQKD=S$!a@lkp$Bf5GMw)h`_WD4%tKm3H>sjs%pm@U9lFx^0Vq$~x_w`niy6j;e zAY}FJv(-_=n$d5sqRNmG=v!g3O6J-SD!i%jXfjv4wo8S)8bB8@x;sYF7!q6qTN?&wvO+Sr8 z0o1(WxEdVu5k}45g50sdhHv~@Ub9#@^aZqTVdhubZ{SW3zhye<4p0+Y>fqq(%B;n&> z@#f6>K_<-U@YKYji6+w<=CGU?>r|MIEXI=j4Co?K&ehcV3hp5#-y zm7O#nWtu1$6{wu^u+dgsNv{~fTX(_?^<0J%hek@6hG}vX^_}?x*rglt`!T5ij~yM| z(9tkQHY>{V{J@#v0qOWlKum}vgGMrPR3J0fz`Nm}m*!a^=Edt9v_e#wft6kvvHNRKmH_c}PMoUzSSIB`#qpRrcp8NiDrcg@VzbHAV>6LB?5x=U zi?!fA<-va=Uoh?>1c+__JxDqje1&_P1x3&7cc0S5Gb{ z%KI-lwTa@*1Wt}o>$9!ev*MT8wq^iBej8N->7(L4@&S#&ALVD|d;0H|w4hIi%nY~6 zi|lm>9ik1S$FGf`K7EPj=%2crht^%PgT#3^){04w87`?T-iniUY~b-krB?4 znKsS7c9oh;5DwEXM(Zkkb=5}dhI#^PbHNJW>W3GrV}_08vmttI$CC>-nu;EYH$Kl* z;XAbuS{npj9O1kJlth&_q}5XHp#rJ`nJ!fPmRC1bInjXuH}(fUXgen`ZEz>DFJQSy z?fo!4;9Gs&zQ3&Z{OvPyVMeUMKG|`wR}z$ov=6vuAAA%K?D4hVM_TqfHfp;yGpoVN z0I78P@qj!0#M74D32D3K^r*^Fx63wux+avnGa;R|WBq(@y-ig>YyBGT zGCV9^Y-?n!TEC_xj2Ax0s*kyn#6zZ2=c_VLHa%wY`r3UXpHi={T5=HiGl1Tc_IIWQ z@F%;mR@+^K@bM0Unqt%5gESz#N}H{A0Rv(9iiWL#93O_k&g{633@Jn_gKH4YoZE6~x^<>tLs z;ZhrT^JImOC_y^7_h<5WKQi^#zqVYLS+Sn%XRE0tk)AiT#tZO|o&D3>Aug^;pPf>b z-#{aEVwd_W?AYlB2s9bF=vs|gRrC3;0R9w}!BxD-w5^@h$?mZp?yNZ4XjFE#9!s); zhZ;u5W}MZ{B_QnP;j_zszD$ObvB77G(WH1y7d36VaRrm|o1T@iaJID)Fj zpbG(f#J9*-fn0tbuQ8B2;VkwvDEz;|5qyb!fEGhbg-h^LzFJ){zx>9S3#H73DU-!N zg|N5WDi5@_21d?8^|*q|uO**i=EH z7#Bb6UjCYNSy5%io9+rKlNZ654~SADQ&1s)uVN_fG6y(>Gig+i7K0s2i7Z6z(P|&&AA3)uK|0-h8zlm-7&iyl+ZXZEwdHY*~twT6vRt!o+Wkad8J3aPGrt^b8 z$+o(`bO;-u_&qs){y;_!^@QpESB~U9<_ZAuKAHu-KVAB7mtbB+WT}4u3cg83jS?i~ zo@_}miy6fm|K00jz0Ly^>|&HW#9c(AjKFx#iYGmuZf}?Ma&F@Z;32JUfAw$g?g|YR z+%6si7q5G-8~g9O`?nWM6`K+NcxZxpk2zCvMaA0b_oKDgklbJw%@7n zO{Es}E)NsxiEs|;Z|v?4ef&q8-0_RKlJCV;b^JhsKN7a5m-*90Q?DOj&duDg7IE?a z=b0Uvk&`=i+A>qJiFl5wu?X(E$CJ5*2tRW341LihLYA=6g83!CFsSPtWto&D813(t zz|d8{tp9&hvKzHXcu~L{5w^XlX}HQ_Jx_5cL$>Z}&1d{{B?fW!j4%NIe+C)uXVFnD za?Yz4O!!x5(fM+rA&Bbab{Ot~a-uZIEFK0fvp#4^F3JN(mTpy54Lm%$WFYO9}XN7hKg<1e8Rxciqa7sAxHK`uu}s49#2TA4gF1@U;q~r@G82Hri}e|jXKPh(N*i? z<8JTn@sv_$C2pdGo^?1Utv9OGizsw4eLb8i|#Pr2%9%YfV-|s_^#b0aAAJb#|u$1gO zkwnhcH!^P^7>j8_WZOZ!gb}>(oaxk<_e60nG88aK%~S$;!I@~Mpa2)_z67!k_zMkqjkK9FQ1>OMz;b$|g9K7A2bDU=5j+xsQNt8KSXzE_?~Q5kH1RuIX2bdu-gA=I_#PLWLlbJXiTAVPZ~0Q795mhINFUD z(si9*$>#)Pb>3G=|4k5l`^CYSVA?un1i3$eplRV-eUhp;MuIIRKbO0wq=Ehv;$po3 zKjT`KmPnV#TIXi#kkx;B*JOEo7_0$-t5+_AjRJZFX0B24Oq|2pZdWx}OWCvs0g8&rUzr z8Aeu&duSD1qZ@ZkmDK2wmSYs0^Fj%{pO#8*muV_~Au2X~fkOc*33l@6>Wqzb4sLO( zkc=&N2OVQ!IM&~Nv76n5C&w7{PwBd<`M;DdgYGMz)MJGMr*DQ_DJ1lNl8wxE&-v;Q zRcWx%No!cK=7Yvdgy6dN?64#rd#YOBwM$C?OZSL)=tl8qT{S}SXm|+Y7r0|sXVi7O zR?Ys!h*QPe`NKvAsNeBJOfoPmV(BpA|8n9vbScc2OZM4ibnbm=T$Nua&mC3zeg1T?N9M2#@+*B-wq)FQg>YS~A`PoDl3 zVyuq--ab!G1tSaGWiiMwHIz(F5i3G~qoG%H!DrEmQ!MUdUF^T$@YzL$@0|1o)M_IA zpE_58$vPF!uQIeZhO`CyD#n{1D;fz_?Zz#LM82LsqK=%KsNS!@49QJh`>;-6STZ>2 zGVQ5Z(nQ9@(tH6%fiycDMfUM=N%B>EMoI8vG00WnL73^&KMh83XIj<&f|J$hH!4l3 zrEjGCPv* zt@5_E{J67kC zJDc?VP@1EoGPa)E%uS5ry z(8~lv_)KzOd1F@V52m9X_;2`|HNKFDzHMBsHmy`VO3If^t}$f9`YC-)X|9@VRmH`j zyey4#CQu5U#pLT*9@&luOnsjs!U%AD9+KdDtqLQ?$sq zhh)UW#pBEw$(^h=p(lW8Fq?a}(GmO$NLC9z)i5xMbKsAH9^2vPWt{AXG^w{%~Ky+l?wj;)xd|8u(f>QLJ}hfZLN0YU`rtDL2B zdFVn|THIqeT4!|$DeU;I8IBy#e0EV`M&%zd6; zh&m5&|5_C|JWl^!A;0`j>w^BLb*(x{4S27T{G*ANN7>Gfcxs?$AiG*pk9LLi z)K_pcRXQ8PDYE0(MmUxt2Jg1woO;i>gP~U>Gsu+jjiVfnO^uZq<`yzs=@eH2>q9(U z8TJqam>gm5A`CiK(FM2Ne4Dii2B;XbCJQaO;2aab;VeJ=Cv=&%^>dq6f&PyGs0mm0 zGfDa*(;<=Q!5mlr==7toH4 ztvrUmjJag0Rx0hlHoO(OSyf<7GIG(aYN+^H$nZxCSe|JnXEbSa6jE(Ow^j@I%6rX^ zFHY)iC2&yDc#g;%>>=4#OEv&zjRY^9$7BYgyPCZYtfYLuuj-U*0rahIffktm7VQr+ zrawMcRjTSvm9{#Ba_z)74lg9|%OX(zXz4BWQIJQhH|dc}t)3XI`|&cy+St^@*oaN( zj0^BzCW6LfWY3~HMqIoJY6pCCaKEUb&~b%%2`VbIp$3U?RUwT1T4uJ7U}u2Ep#eE0 z@u+7#ti4DeA1!*h@;sTNw*d8>MT}s7D{IBqd|#y|)ad_uZ=GEqnp|QvcZI{O=Q&$w zE2x@QKQp6O*_}>#ui9??4A$f{aKce}5_s83as#Z^mAewHEz^z{Ej!56FCi{j8dEBA z%Dv;y8YLZ4mJe7&rW63;DxAhf7uNUi$_T(=1V4SH1YqC-VKN>stbMGTE zo8h(3ThQV9wT%$hrzFJ&=P(g~q`}!&;u{xPgkEQ^=jipYYa^-j(%Pc#6#I(f+#7pi zwMAFo>Y$J%05bg|QLy%0yu5rzj?Pc5ZpLIOoS@7FQ~D_9*aJ&t?GH;KH|wM{mI}>z zXnqdK^ZxVx!d{LIlXUu{6LV8;bkaEi_81l8G4uWQ_G{>3ERD{x2si<5vtT_iXv%@d zSjY;Y89BpP##T$jB!ub!xGu+GO+gg`Z3bfjG;BTq6CC|=NrWV?j?ZmB9$l+5`6|k> z2al>92Ipy@*UHqGL^<(Hs>iS)3zo8Nkn<%}n-tEC1jUA=YZgfBM+iLs`Z?9p3Yq~$ zM`BjGIxP4xPneo3&C*h=Io0uzwQ*W7V@_7m-8J}kV=gUT(-o3UOt;ks;N|5DXJ;8+ zxmF<-8xmFokr`o{1OwmqPH3S;N;Qvs*JB1KpxY<;o`FBf_dUpVZm^LGC;5I@)?Ajv zs=P`7Ys1-O(=)GLkRsDOA=gtLO@R!Lf+@{&mMM?WWn^JW--mG28CezzzdAnm2OB3n zoHg(q4>h5*Te&qawP(U4=rS99L7G=Vsn{l8PsDH`8{^k5KK0ShE85>iBXM zv|o;16U8Pe%WQy)c@w-u`MU2Trh)KdQY<01a{ z&X9ELEeN_bj|c`LF-Zc#IQU+=YQJklYv!sv- z>hhV;_NIrUUoIP=xH>)@yHZqL(pb~3301fFAmC)JguO$;vPjNzYb-XvQHGC?US94U z9AbUjfi91IsX3T=h-zR1Aa{2v>F)PQzfZn1|G;dviwP@jR@1T5BBhx-`DH{xxqIU# zfO8+1_oYf?N`*8|c?JR!h4_@t>;*D>GDS0XB59`WW@RK&utLqkb^fZ{tE;Ue6-cA# zhM0oLYIUtHI{#=cIle$$7yS84hafQs-ySzKW_Gn@P;Lh!un?LU$+&Jffq*a-!H2No zkgILy0%?9*moSCZfzw*>5vtBrcY2rvAS+ws0zpc}{GGQKXVC(-5=4_(SSTY5rXZ)$5u9{VJ#N55~dY1 zz;VSm2KTDhA(ru+mX0oP*ibcP?H#9}KX(Wq0>;DbNqZCkM{M!Xs!@tupJ&V{c~j;M z3rq=~VXCPHuU-}RR1F07qT8ch{%*JA9VND9c3a%$X%RCfuO-)-WoEQ!=I?bs!JaXe z-f}2G2M&*G7HJk&yEx^ zk3z5ZkR0}%RRghprleVF?1oYU4A}SSYDqJNCT@4ZsJ6uT(TvMruy`oOepKvUjTGN$ zy9}Ul+vEVZP1;Mh?PIKlU)$kX3*44Q&>cCV5wh&1%@U=`ExwBvN5@q&-SE}i?D)&A z<7Q25frVbx$_-uZB{u`!A-@>)4pqA;OVa%(DC*6>m=*iK%4mJF@^phhUGY4KWURWN zs$TKDw?v}500>q8Hfkxktd(2eb^^BovW3u#8VsDRJt%rQ2F=w)`dOWWD**O{P=v$% z&28)o@N5)Gf}+~`99^m%I6HFL(8BeUZ4{f}Q++cEp_Sbr7jf6#!d9jSs=|28S8(y! z8!S-w=lByC4%W+ud<7OaaZ}fM%KpWuQ|PR{8O> zA?RI|f%i^nGJ2r~{8i@D-HxB{m;Cy>A>gfunTw9wiU70B1(SluY}d3tP;giT(D`ZT z%VSeoiX>t3^rU^}SEb15i8t}lu@;vWzNal?%DpF`q?WU%jO>MDX+|Y3Rc5^0GD*ZW zI<2b^WtfO#QDoK!!&Mzmx1LU@qP06D|FillI6Z;838$=#!24gG#Hw`pMZr*S{5?pl fuYKb2;dyu-o`>h*G0*=O00960e{DR~0GGcGB^RZQJbF#yb6d|Gm#Rq_6Rnyy8#g#$6@#u}3zCNl+TD3XNLz-h565kf?nlXGQCArd&G|HOBO zanQRuC@dT*K0iFXe||NUDei&(UH3uHdB{&7PLFjGq`WKS-0SPl3L%fTi`QMnVt)gu zYA=M6iVqdgbQ=!Av%}qNHfXSTpPV4!TqNw+^YtYExtizipqxbF3BG=gjy;)0s*V&T zU`Y-=bBMA8ki&i?qxV(ELn(t$lA$V&qcz+_w+DDFz~jhZn^Lu)R^}$>sBz|6-^y_k zWEciY6?c+YiZ*FpFgIA7L{2#bM=zCQqCNk?jKA|1E)>Udj8~ef%b*kgg9W&T5|n7dn*Y%7o5UoZzf z0-!o8WmeZb2*bw@lJCCXeY#me&#;PNsP`Zn0f7<~?lUym2$y_iE%tTyiCuR)dsUOAO?7Y}-y6i*jTbC|wqX0PEOiJfM zC!E`{?Ahp_bf?+j@ZbnDQIzeb38vbQeEfr7lvV|t01gUI1h9a8T5e;>8N5mTl!fpN znM8SdEoU`^0%F|GhVVsu%Es^`d_PU_2E@^&t5~XNiv=+K3>-R2ax^XBAl<>794c-3 zk*oM#nFJR%*@Q#pA>huO`eaTv08!tuH*^wFAqd1Dy9E! z7|y@Dgx6(PhW83}cPpgOwaJlh%A(QEQk|9u9(uGM|b! zh0{z@Q^&Th0k4HD6TSd%4-=zF0R2AMY#ko7MIL8_{;lhq@?q$Ch89U<(0x)~sL)*S zNI<@ylRtl0xicnOd~Dlp4GUq0+;MDB~IyF zX*rg(u^&Y^f{v)rq!`+#QGy~>%v!ih0Sj7*G5%Rz&)4b8{@vk4a{Wc7u8OorDQ8iG zQNM1a4Kcr}x^0q;!o<+7fwaS96YFs)al3$!r!x+5ZqC=|;bR;w?6tzQ0z>3o1vFaY z1z%Tb<1(})v6W~O@7OAGL`A7dCEl2XuA6YbihV{%cyzgzjB+XhZ{4qQEqwi`Vpg9M z@R7R6Xe$?2F|%qZ%K2>T?+WQ!bQY$Q56C8fc1}S_81MSV4WZD{-ElFvb=r(T0bYuj>M!$`?71@e_tQu*(!a zs@X_#$R)ufwN9(2}-yl5PrnuK$dd(umVMQGk!H>*MPz#0$xg zAp;F3GDL02E2y5s7+sGof@q%XX$EcRR0h2RQ52Jp84u})H_$I$2)dWfSFw?thy&h< zMJ3Z5T_rS6W@v(5RS*Md^qCTK6p=_&IXA>C1^pBTvY7j5jVNILIY!u-x;t5D=jwl?5EI0-&{>53cBI=?f%oR<3DH)_{Rb%==X$Z!!PvxSTIO{Mcm@vzAw7 zHa0QRi7l*BErk`=@vjC!!qt%w%fLd?fC;~?dUSlzf-DB22@hViP!}x?QhNs5X$%F+ zWj2bVnP@dHJ&hJQc_t&87>4FKyjr9p2Ts;BJK_FK`0X`gVEb-9wK{LUCoeHYvqOH^ z*A5k;%bQnA$9D1 z>w2d)QqgT=s^XZ`xG;tExR$w%G-`cY*NoB%-mDzY^{R=;%37wul2V81^1-HV8HWhi z_&6FeK^4U6GH&uBbH;pJw9y@698>T)a&oV{=;iZijZC-=W#ObIR#%ZLX|}MBAAhl3 z(1UWlCYpk5#*u@Px|OhDTs_z{8o>@I331u1wdeJQ$W<7@G|XmC5`bfy!S-4Ey;_Jl#m| z?TZ2aECiBvb2!_)pO&A$T#FxW#$4_$QN!2s_+=^4bYcmhylKjaGJMY`nr!5F%kboN7vLuAT*! zVU5Rty~5aB|HHH{&rL>lkZX=RE;W{eBiTGuk3y=@yim%RLwlSS$;}lzV~=Xgm>dw} zD8fA?c3-9>keqZcjmLc<#vP@11;irVff|baK#v{G@XiNoFW>g+qDTYYc$@>gmt<5`*LpLwec)5ho zQKtq8xbXOc!Fn9LEGsHv$r?56>cWXZ+l^V%kh*S=AKD3re}!qFJWV+*9F`y=Np=YA zzI{>5*TD5_q(bMcjQli(0kh-mO%GauYyQ<)js6Qdd@S*?@ZzW1pMlNS?BHN&@Fv4; zJEeqFb=d%glei|y44q!hRqawR;bVDM|a3SQ-dVi`)8E-Z6o%QQVs4jswwYcNN7>C=^4ps9f=?V-3c%xb z@w}XE#vKwi9vKBk{=fMUGid5%$df%#97bM1p^+2q3EY5Z_D`4-@z4LxCb4i2FK79 zjtQEcps{e+gK!1Kt!0g=U0rUD%!ePMjgnY!Gi}otA@c|pat!W+<+bFLbt%xTAN~3i z%R-7(Bq>!sAUQT=xw5A7&?5PCjfa;rDH3Dg2&!l(dt!6Z*fQ|`Y6=a$74-44?>I{Q zqTWPanzNk?b-_te+b#XbG)u|nH0NE69Jt#Gcj-Cj146IJWKyaTnMJ#w_=j-+PAYGF zC)!wC(yQLv&WU;nOwmz<+1PuH``cLo#z@dFnY>Cx9(`Bn;;U)T&dLZ_u3RHbuHhjM z>UN#i6q>9FZ`=mRuK4wUQs3)a$ZD@{z~2~W0V!7xv{b@# zw|hQEhn*IJUhTlvFx~42ps$!qnW`*y0wegExh;NzS1z1QRJ$*vj-RTEwSze$1y8cg zNvxhen4_IACRYnP;ESC*p+eiL0dnI;{ja&%Z`ZL=$=1e#S{t$f5+*~>(u}TB>7s#n zYl`ka+Px=O@=hL(s_sI+DWZm*#g7f+Mt?F@d>YDxbMol@WXt#sSO3do08(A~`$ZMs zkv5obl}*L_ zvxvDa5*Cx{7So+eXiOF!a;}VtisweH|-+vg9vuFFP zp8Pi<>Rcac#ce05`=ix~jIR6IQ_z@V0NA`k+qY&hI6=LssCKV1DMI4p9kSdeW1I?g zk11kxH0M)KhfGh#*%cjBuW2&yAC|V8Gr+h})6kLcpra?3wp=@k!N)TM83>iqjO=NJ z3K+oGF3LqHJ!dsxJVh5gNO z3LcFFPQgUhId8|ei%Kc_n&y^l{y*LOe9zQ__*DIGZg4qrnovlWZo^X@&W=8>v4q)q zn!xBWWmb_4#L@?m=?2`?@pY0^N&96fD@N?h``Hh|gsZ5pC_i_jnJ_bLCw1#Mh0&?D zIjIwe9>PdItMqNP-5}%ttybFY`1-N&>Y&N7teLS`dM__1QG%z*X3T_GArImTi zNKJ$af(h0Hmh*xPjGyqsM>?3Y4t2)Pfq1i=o=dj)ks2!Z{v-QL3wkP`(8N)XPk`|SUNJqBVQOA^koV{| z;g5?p>ww#HxQjdT*H*f0)QU@psmg-gBiXlZpQCD~0X81`L1T*kNK*D9xg^8g&NX>aEn*J6;hrn3EXLS>zCQNenF@NrEGG6ZtDF5X+y!Cd?5) z7kH_QFy*Xw=T$uP>tdVWIAsPx7WcdIQXY_Z^aDdg3wkv;a!*P41Y#2YG3;Rt@+-}hzh;xYXisGI;ZAkp83-d9~BeQSi^7B3kcy*9S>b)VQy zRi3;Hr>?VfQPVsH^FEpu{%KE4t%Mwxd-!y4Uv-xpC*t+$jD#L zg_lP#OMl%xnUIXHjaAG@SvEGdvaSAW>Z&%yOsST}x!fcxxy1AxZa`eF|BK8>i}IxX z4>iFq?Z61^NSgQiOnvvIaOc9H%u)ZO7y(2Z(kKpb!d1QEo9|uDYuyIh!WuJob+fg6 z++<|3Ii7eRd%@;`BS$YU-sHQoBYTM`ewhFyytKVXVmtt7t}dT3Jv*BtlWEmy0Eoc4 zP;IKu>0#!%w62nao-ZFnW8Js%udx@P=|xUByn%Q$zIlH~$6MuuGqI2aimG(2Ytuf5 zplia#M4NV5TK-OERqI>WH7VaWLc?uw{r#;6DBISL5v&cTCMwZ+riz*d=3-W*yZEDG zw5RHFLu)ah0ct*6Eh z`Ix(#0fj?O{s8ZzLmySg&y5=5ZO7<-IhpHx*;Y=(ktG5qc6dw4TeX+m+k^+0VDJ;* ze2~soq(7a`v&g#U5sLl|nRtkvy9!^M5X+%w@u0yz2VsM?^W47pGQCgzEap(VX%b0b z%9`M8m2G%lH&&_MCU=%`p0Sp%4-JxIYiGg<-E?%T_3#whvl(p1olx;*v6ajh7Tx7+ z|C{%&bF94PZZGp+_e|^61j0GW221257I`8XH6qP)CL=OT)1$eot6=>GutY+>VjdJwEG8ajDmDrdXTrjrA0BwCNmFheN4m= zOy*P3M8%1X)eQOW-B*4?F-xkUg^QET!u3a%;0Jh#UpeJWJ@)zV;Xr?Dnq|O3%3ZhA ze%nUV?o(e@fcC1P%!;72r|iX(xc&BE9Vhjy)zdsix;~rCC0nqCWfK6wuc60eRXQtf z;DV^>^wBnD#;PfRm82bft)GLpbK8Yf=y+~H((1P^+j==v9cr*qqK&wjDmhEUTZ(>n zNfnI$t8_eOJW2yLOpRj;ZMg;EW+fa?qG*B5#t)J40ZF6w!CJ8kaD(!?Mq69nJgu3C zlDAuF^u;q3Y{HtV zy`$v(KZOF@h#%g4pN~~daYg?oHc=McYNbw2P4uMswcl~bV>miri9*JziDP#5r;cQz z=oVW7MxkZCi{D?yN9kmLRpQ*}1sh2+jfzjYx$9zS3O9Yr&o~wV(5nyS`hD2K@nN$$ z&-v)gnc}n?YTu+^;vfDFbY=;yj(sJF>w`PJ0dgeHUfFF~kl_8%74vqDFltr#RHwL` za6qfBE0MyWR*YRYQ&5Y{CiEnS)k}0d{koZiT}WDoi>9nNwgcQDS%Afa{M1HcmI1f5iysh%0gmC z!=WvCBgB^IZ90id!B3tOPfAOX*$sM0cwpA-FE<9NJg546$(70#Iq*nHr5$_LF?%9G zskG}#bjpf97+QoqjGoMFIXFsv3B71>fd&AwPSk3OC+;%P_2yrwurs(PpnIUj`+tj! zBtlnyKWaVs0!u9VF-uQ)-?tenIWrs3U+tgoPh#noc>VH%M(iBrgM8SCbeMmklhibQ zD}Ba&M}>mK z@ueYxSrj`Me9YTiu=1Kg=0aPCjIuy1G0a#vyx)&jZGAux7wnk28el$KsQ2+r<1pc| zaFrIVNwg|kBF;M}2|j_A7(IMR9m_3WZ-?s*JEuStyFj?B#4Sj{twVT;$4B|8>Rt1x zhG9Y5uxMIQ75a2$Hh%6oE3WQ`#TpG5zvIQF9|$caT8o8g@^#BJ zs{h-*Ll#-2PvB3kq9a$(I@MOacU8oFjYfCaiK5Me&^dk*xsiyS`VKqKBL1g?14yf< z7Ib+jNFd-n3+f)ezb&dG8D)#{T7JHHbskYffzA6jeTd$n?kb$>0l^@zyk^_?wFJny zIiE!-tCQH}O)5{zU4G-s$<8;}#juv@hiRSw-iWf8egt%8oWlJyXO#A~Zb1}vurp)8 zpID#ZT=gh36o54>;WkPue2TPRDAB)MWCm}PO2>C~(~Trty;AcC7XHD(vZbH$JWQvg zt!sSP&^oGmn(bAiWj{*O|7A8nhlC7X!0XQ>kuU%Uh1a2cPX?>+mV@%!!|0hf9nNq6 z7X8}76sKzxrW48(L4*ffe5F5blM~%9r9B(M_W57oKv0=tY?tm&pZvxO#5p3@Oif&# zP%En7%L`B8mc13DOJ8a81zs}z0u>Q+VaOz23})&00aTXK!So!r+oAPx%|+ezKA=yc zbjy(j4@f>GIJ|9>O81RwY1P?{1`>t%W_^s{#(pi3D%GnAVd$gp<7MviZTZgccJ0?^ zj|$)D(m5z!$m7Yy=<^zt_@l?*7t0<-=u6I?} z7#uTQ64Eyqc!EH=_^KFI`2$6-7sOR|IB&kzzUiXtTtq@U#U5iZS{QsMVYNQXB7A%- z19Cb;;m^81FOQnAffVx46|RiE$-HjejuJ-)1WkvZ0OUP`M=YX8kJnr}^|iP(pJx$m ztH<^05i!>KLNJ`Y=)d}Mqv+xgm=(}Dnc2(`OV7uQF``16$K6lTsIr=4__?*@ZJEa3Ye`=+%Dv2igk<11vD3w*RjJeMW6{=J-bfF=~ocHqSN#U7DS06;WyZ1 z{Rzgrr{`q%P5HuTGO*uN>dw^NNmMzyO>WeCjD~vJT&_6|-HNkKX!zp%!}+>4mx_S` zB@dWQ9ku!snpVNNO4yh}`TeDrIJfT0_AjUjsVj%z*VNaJ;q_Yor=oYzCot@@r|!;& z479^=m)Qq{(a*eU8k}LSZ!$ilhB({E^Awv?hamUNeg=i(;j7j2zUvi%xv?Kk zf)mejTb&G=K6M_M=v^N2M@roXo0O2|M;$Gn%JM%nYhV;BK_w%t=wjk z6oW0;COFr0)bOt=*XpZrvw>RBX~?bv`+n2o$W?7076c|YjpTNku#Jy)C_A$DtyU~+ z$;<>e26CA7s!Sf5U7+xp@kfK-YYj7Evdlr)QFBkWWgPJxGH6X;O&8ifXDf z`h&O3>nZrdQ-H_V?LqLg5B+lcTs&HO4y_Zgpf#T}|fi)(@XoL&y45a`z<7O&P z?Y_rpV@DpLIs^0`R2DS!Qs)OU`tna1S@~;~TQ#2Lthz;TeEtYpvHrV}!AWm1S1xl_ zE%|FK-6?~BH4J8H?jmNT?s=(cgR`*ApszGUTH@f|M>ppy=XHpw#L>|TlEbzN=|>G|=a?TJZIy@nMXjD>bfWjV zS*^vAOviPG`&|xI!q;h=hQMw>YAQyO+rh5xvuks)WVj;&x+krAj=zokw^HQ<{AE^t z=I2+$x4JN0H@2CtPz}K}`)Hr9u8o_ytx|>W{=`ha%Pt7gsMb=`!1Kj4YgPA}_rZn> zuSEfBS=^BKCEcnxMO1wtFAB)f(+$6y*ZcGB@WE9pbXS5=fBRW-c~e2|8^jIu<;`WE zr-#?glLz3{j!52)yq`=!sMF{9ZU2Q`fM2Nln}@rbQqLs6fcInE!GQa-)DJNOE@F(D z#rx3jUha-h$5XcwaHpOQKeRq|&*{&s`G+Q&+9F+PEpGF#SM~-2fq%I|SJ7H-vNZiP?i#Tkh~ZeVGqZlvu?<%pwmM5*xY zyga?sJ+E5!_s4*?M}TDwaVUYVjsl%uvmAr)u8>Lgg}TR^3P_(dyu4%JW=i#;3@247 zJ!9!SL3c&QOShQr%Q9+fsW-X?p1@i&V2@@@fn;CMy=UKRmwma@m}X{?r7+1HZ?`9f zeY%Sp--39wl~Zs;mF~3mIXxaJs?f#k=ZR3&Vb4<56(K~u`WMTvKWgr^pm#Xvi(b)0 zJP%tPweb1s-Onqxi5=(tkZ{qjVuFIZbdTkY<;`+ksz8D=5#7_>1I2+;bMM5j;ca=3 zdxPDb1n4l;j5-4pBpCI#F>~la`u9X$+`5q4 zR$eCyx4~!h#NEerMs5E_*cJRp$7_#}<|63neTHPer+XaI3Wh7mqly=Wzf=wnS0G~V z*ce}Lj!p$QjpE63fWWN8ErX=QkxDtJnTR(q*mR0Xt|iLVWA5Q>|Cnp;Xc1;=YhC9! zSY@LX%@g${6z6@&D0?h!`g0*(+^Nl3&;+P({g=IKQM7Ryg%`_;p8alNk1C>FHD^2d zT<-;U?D}Dt5Q403yq5X1 zxW0M44|@f1<$8UbIJvQ3yRev2IrF3bFjH>~b?pi9#<_2>YaC~}wJ0NlYdBYb&Op=H zLXR*dT$QDh6|;>zF~_wU)g^{>w{7w4ocB>|n-^+M^9-sGfg4K_oiDDzW%Y=$SRgNG zEI~`nfUi(wxPu^fVhmZSSDGpny*q2NVj`o*7~W@8oL(KzMm~sT&8hb3C&lm__QTAkz$(E@BQ;ez)NszBt;>UIj&4R&pQ1m(y}s9xJ8BVvlcwM6>gnEHz)WU= za|96ZytM8`Zn4()I;J=!nltw(utbO zVmu7tZsNT&LFdLuD`7bbh5?G?`?gGjVB!!d`t`l2<^X$SNUYs8-2DrL;q3-OW ziuA!Ucb&vOGmC9+qT;0}#($FncZkj6Q}bvX&A#xvvtm4)@G*86lH^kr-8;GSN`%wF z)*&6KCpcQ=TzRL!`JDOZZLV3S_;ZM@s_1zi@j!4g{^Ol%>B*GSySAKY!+NP8mcbr$ z_!E+s0u~o7mt`+u=f=(Wi0Fuhm-Xy;4TXGZDEz8Of!~(ye`yueNr_i>u2EJsgzCa6CrUxR@gM9FN9CZdRkA*a8rLj1gz}cjrCLi zw3Fr3Dmw96jo09;i>2K{*Gp2b52zc*BQPFcW!W5dv)lEXy|E>)m~RYsA=9Fj=vQTu z@*$|z1$U9%)-BqOpIUVf8MJ&dUL;8)?r}l;*IUkCux;#NQ%5V5c|?aVOVsPyUQ`F0 z)7Hf8>giRh;5wiQ>x|q(&DxH?@2&z2Gs7G5o}p%E-3`FFj_k$gY>DJ{%AHK8B z0FDBeEOpzzhX2`umend{*jZKQWE34B+rr0!fdi+UZ0Io?Vf3D>q9N5IGojW(YBJeg zly1>gppwT}wk&-G_TcDmICk5;k5ywmn@SXLY=hZS_&D-Zb?BT=kMc-(){&EsN_5c~ z|Fz5-`LyBG<;b|3Ob=3#rdU3E>!Ru~!=qkDw-bB3ERl7y9XaF+N=#Sd2CBWwe`CX+eG7De-R6X z_?l)7M$XDyWSud)7LAGym?|${H;_5#xpvSfCG4|>Xv;10RlP>rZf%Vixv0x>V{bLT zVlV_ZcGTdj=SR=5zr4^VKIn0-4rp)?7eq5K69;;Fneo@+C=4pSeHd%$8H%R;r2xfsh*F8rBXnu8{-a^Hw>r#rI zPq2n-z)$m7*2Pbyb|Z(L0@*4g*eP*)D(&c52rAC50^OY~L4M0C=bMzq;NN8rHl$E? z#B3rS+g!lTmd|F#sR!0AjjYg59J#jP;P|E6uXV0Xs101gx)4snsoqv&r_LxH@o zoMN`%srqjpq>Y_bSGR2=+Y6kEnk*PGD*g6knu^Pr3N+8{Hby+N*8q$2r%7*$G%E~i zX&OvoUnPg&m|DF8<{qmJhNmA6(0Kg%j-^*iuWD=VBwR(OC)+;`B?qEosB;JgStO+l zS#3pQ@|?;5w|bDc)s8ul`Yxq+zuund9WX4>1M?M0%(-UToA~YgzY8WcmJz4u;@ME6qvoC0*AlEnQfm+SthL{DRh~*p^kujrwzu zYppuRX~uY7Y~#%O*{I=mjyxvA7rkgPfdG#a`*I%k)qKxic^+L}Q#+G;f}3Dj_@N$S zz8*uzWINN4ok;g6O=bYR3F9`l_uSqsk$D!#CIT-=-P$y?BRaCj*4jzEFB>L+vD+w%e8-$_=@LyS$-C%rSvr z0FjjzS`WBU&oMnMa~$W`gvo@9F8{m}v0SFJ#mAAnyYhx^9mExVxcTICjroG6m31+I z)IluU#88rrJ1&LXh%;S6w`^M?xZ9wmkMY-dFTDSE%?_7>t9HG^=? zlzQgd0zgZ))BfiF)R#xcj`Kek9*DOM8OfK(3P zA4;uX+B|{hE+Fvd-&s$Lg8h5(`CS?Sy~Bun$2e@k!MWz6xpX;uj zxND!O5-mArLT8O@_`%IBbpE|5E){It=c*PN&7o>Gn2x_@1LK*q4%9U)F+ZVkZ;OK)FJ4;{bYyy)Ifr@tD5~&jU;vc-7_ZmSxun_+HxY| zMhEK9H|q+CB4 zmn(2PFtw3OzWi`AhcQ^C=t7?zDOHQaNZEe1Yd};c)vEAV%e1Ts@D^DzQN9!kBYK;A zjzr*iQUG$}MU~%4W9b&I6zlRVqAt8`4?_yGaUy(6ORf9c)AC*XWoo{kWiMjpPt33) z7uj#c&XF>0`k$Oz?EkvrX^Z+velKA04!$25`J~lngcb-slQ zs*CFQm%Mq#qfP*U8HQGqN*j2)pG6(DtC>t5t8mnM7jzoMIPA%A6 zT#h>O^lTo5X*BK{MaPnNm^A<$(B<>Wh<5=Uly(g>BRP;(^m!rz8Y*|}*-#b0UYF_w zXh1F(od>sBMvqJ*p>pJ(FBJp@O zllBDOKS?iqjYi&|m||WU>vc2*e2c3817?fN>93#HgTzp`(4b!VBkRyM2znlW-EK!P z%DuBCon|~rEstk+0%IpNOYp_eq#KFOeeIrDVziDcWCfb6;pF1PTYJ7=s#K?QW5%D}-aG z)UW0tBGf2&7oNypAJ3z34w)_EzwfUXQwL9$CYBGR8K{Q0;;2d%E#orw=JGsoqO#r} zmF@RKUQ>LY|IX9yDjA(_W2EU%geIzzH@w&6{+N%JBE%N3H!ILai@yGqh!eAsW^nb4sVQd ze>t(Vz7+_duWXpdPL%E0b}6sCu#bpRE;w~dS0-b(A7eD|F+2fdk7bVDxObO3myWeK zlgKecvCfb8V$p3zR|B-Jt$_a&|qEw;r36)<*aGfcf=kk`$Q z4i;2ktrKo_u@~nhIm%J?W-EF;mlpQ3a6Zf5g7ly8XY$ev2#S&?>fRZ8zU$n&&Kf*6 zuzfB1Zt6TXG;sYVFYYx3KF`uqewcVPjKcRuAF6BPy}b6t?R7u$gxQ)!s8G{C`$Y?} zp><)9mCyB+JEhB(g%la*vNXF$svmC3b-aXT7R1}0aA*(Ns<%A16zCpO*19y&NliC_ zaD64%R=NT7W)So~*Rm@4;Xr}Aj>2n(AF@^ zr75A%OzK4qU?3az8ULgGfa&>Dy*DiCx}DqvXHJyuM&R@3`Uu+n@oL;;IXRsoMlD>( zRtNU4nnH&`@4=YCbM)1_q6B73(Onc|iE>jY4AeprMvPnf^zSi=B0uSku4CXG(BcV{ zDA@oU>=8R)B62?*$wOmwkGGx-@$%QJVUx=;m z;^uS?8+2>|5~-8FwL8iq?9?W@86f6+$_3(DCTm z4D0T|83*5R$!nG(TYd#+-_slt`HSlRyD<5S`tAD5h3d8banAGB-e|gwR%({Ha@}m3Vu&)X6CSi`e5dK_kgKQsHR9*7j z^0^&cANTLsET!J2_pW;iz#Vmy1%jB#e&NmgGEA??S72Pv|AM0xu#0TeU$|=ASNAI) z70&%-g8G%?kU>eC_K|7*1exW4OkU_-?$z##`!A#mTa)IoZB#{>X4_wEdaGnKyPm_B zE3a6ZL2E$LW1-Z*tT>Yv>0yO`GZp4%>`88Ws4)YoOkZe@8{Uggp4l zVzqZYI3hV5^&rTqF{%luA2aQI3CHgG*qhSfg)Jb zb>;6{j_&do*LJN!*sjv|U@_ToZ=3-kCy2#RelBu>MT@f0ZLUj3krAu2ZZ

>E-$F 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 literal 0 HcmV?d00001 diff --git a/charts/postgres-operator/values-crd.yaml b/charts/postgres-operator/values-crd.yaml index 42af903cd..a66911f96 100644 --- a/charts/postgres-operator/values-crd.yaml +++ b/charts/postgres-operator/values-crd.yaml @@ -1,7 +1,7 @@ image: registry: registry.opensource.zalan.do repository: acid/postgres-operator - tag: v1.6.0 + tag: v1.6.1 pullPolicy: "IfNotPresent" # Optionally specify an array of imagePullSecrets. @@ -32,7 +32,7 @@ configGeneral: # Select if setup uses endpoints (default), or configmaps to manage leader (DCS=k8s) # kubernetes_use_configmaps: false # Spilo docker image - docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p2 + docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p4 # max number of instances in Postgres cluster. -1 = no limit min_instances: -1 # min number of instances in Postgres cluster. -1 = no limit @@ -252,7 +252,7 @@ configAwsOrGcp: # configure K8s cron job managed by the operator configLogicalBackup: # image for pods of the logical backup job (example runs pg_dumpall) - logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.0" + logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.1" # path of google cloud service account json file # logical_backup_google_application_credentials: "" @@ -315,7 +315,7 @@ configConnectionPooler: # db user for pooler to use connection_pooler_user: "pooler" # docker image - connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-9" + connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-14" # max db connections the pooler should hold connection_pooler_max_db_connections: 60 # default pooling mode diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index c46e21e1f..e55da4b86 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -1,7 +1,7 @@ image: registry: registry.opensource.zalan.do repository: acid/postgres-operator - tag: v1.6.0 + tag: v1.6.1 pullPolicy: "IfNotPresent" # Optionally specify an array of imagePullSecrets. @@ -35,7 +35,7 @@ configGeneral: # Select if setup uses endpoints (default), or configmaps to manage leader (DCS=k8s) # kubernetes_use_configmaps: "false" # Spilo docker image - docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p2 + docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p4 # max number of instances in Postgres cluster. -1 = no limit min_instances: "-1" # min number of instances in Postgres cluster. -1 = no limit @@ -242,7 +242,7 @@ configAwsOrGcp: # configure K8s cron job managed by the operator configLogicalBackup: # image for pods of the logical backup job (example runs pg_dumpall) - logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.0" + logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.1" # path of google cloud service account json file # logical_backup_google_application_credentials: "" @@ -309,7 +309,7 @@ configConnectionPooler: # db user for pooler to use connection_pooler_user: "pooler" # docker image - connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-9" + connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-14" # max db connections the pooler should hold connection_pooler_max_db_connections: "60" # default pooling mode diff --git a/docs/administrator.md b/docs/administrator.md index 30b612ded..715b8f74e 100644 --- a/docs/administrator.md +++ b/docs/administrator.md @@ -135,6 +135,26 @@ Every other Postgres cluster which lacks the annotation will be ignored by this operator. Conversely, operators without a defined `CONTROLLER_ID` will ignore clusters with defined ownership of another operator. +## Understanding rolling update of Spilo pods + +The operator logs reasons for a rolling update with the `info` level and a diff +between the old and new StatefulSet specs with the `debug` level. To benefit +from numerous escape characters in the latter log entry, view it in CLI with +`echo -e`. Note that the resultant message will contain some noise because the +`PodTemplate` used by the operator is yet to be updated with the default values +used internally in K8s. + +The operator also support lazy updates of the Spilo image. That means the pod +template of a PG cluster's stateful set is updated immediately with the new +image, but no rolling update follows. This feature saves you a switchover - and +hence downtime - when you know pods are re-started later anyway, for instance +due to the node rotation. To force a rolling update, disable this mode by +setting the `enable_lazy_spilo_upgrade` to `false` in the operator configuration +and restart the operator pod. With the standard eager rolling updates the +operator checks during Sync all pods run images specified in their respective +statefulsets. The operator triggers a rolling upgrade for PG clusters that +violate this condition. + ## Delete protection via annotations To avoid accidental deletes of Postgres clusters the operator can check the @@ -196,7 +216,6 @@ On the next sync event it should change to `Running`. However, as it is in fact a new resource for K8s, the UID will differ which can trigger a rolling update of the pods because the UID is used as part of backup path to S3. - ## Role-based access control for the operator The manifest [`operator-service-account-rbac.yaml`](../manifests/operator-service-account-rbac.yaml) @@ -393,21 +412,24 @@ spec: ## Custom Pod Environment Variables -It is possible to configure a ConfigMap as well as a Secret which are used by the Postgres pods as -an additional provider for environment variables. One use case is to customize -the Spilo image and configure it with environment variables. Another case could be to provide custom -cloud provider or backup settings. -In general the Operator will give preference to the globally configured variables, to not have the custom -ones interfere with core functionality. Variables with the 'WAL_' and 'LOG_' prefix can be overwritten though, to allow -backup and logshipping to be specified differently. +It is possible to configure a ConfigMap as well as a Secret which are used by +the Postgres pods as an additional provider for environment variables. One use +case is a customized Spilo image configured by extra environment variables. +Another case could be to provide custom cloud provider or backup settings. +In general the Operator will give preference to the globally configured +variables, to not have the custom ones interfere with core functionality. +Variables with the 'WAL_' and 'LOG_' prefix can be overwritten though, to +allow backup and log shipping to be specified differently. ### Via ConfigMap -The ConfigMap with the additional settings is referenced in the operator's main configuration. -A namespace can be specified along with the name. If left out, the configured -default namespace of your K8s client will be used and if the ConfigMap is not -found there, the Postgres cluster's namespace is taken when different: + +The ConfigMap with the additional settings is referenced in the operator's +main configuration. A namespace can be specified along with the name. If left +out, the configured default namespace of your K8s client will be used and if +the ConfigMap is not found there, the Postgres cluster's namespace is taken +when different: **postgres-operator ConfigMap** @@ -446,15 +468,15 @@ data: MY_CUSTOM_VAR: value ``` -The key-value pairs of the ConfigMap are then added as environment variables to the -Postgres StatefulSet/pods. - +The key-value pairs of the ConfigMap are then added as environment variables +to the Postgres StatefulSet/pods. ### Via Secret -The Secret with the additional variables is referenced in the operator's main configuration. -To protect the values of the secret from being exposed in the pod spec they are each referenced -as SecretKeyRef. -This does not allow for the secret to be in a different namespace as the pods though + +The Secret with the additional variables is referenced in the operator's main +configuration. To protect the values of the secret from being exposed in the +pod spec they are each referenced as SecretKeyRef. This does not allow for the +secret to be in a different namespace as the pods though **postgres-operator ConfigMap** @@ -493,8 +515,8 @@ data: MY_CUSTOM_VAR: dmFsdWU= ``` -The key-value pairs of the Secret are all accessible as environment variables to the -Postgres StatefulSet/pods. +The key-value pairs of the Secret are all accessible as environment variables +to the Postgres StatefulSet/pods. ## Limiting the number of min and max instances in clusters @@ -503,8 +525,8 @@ instances permitted by each Postgres cluster managed by the operator. If either `min_instances` or `max_instances` is set to a non-zero value, the operator may adjust the number of instances specified in the cluster manifest to match either the min or the max boundary. For instance, of a cluster manifest has 1 -instance and the `min_instances` is set to 3, the cluster will be created with 3 -instances. By default, both parameters are set to `-1`. +instance and the `min_instances` is set to 3, the cluster will be created with +3 instances. By default, both parameters are set to `-1`. ## Load balancers and allowed IP ranges @@ -579,59 +601,6 @@ maintaining and troubleshooting, and (c) additional teams, superuser teams or members associated with the owning team. The latter is managed via the [PostgresTeam CRD](user.md#additional-teams-and-members-per-cluster). - -## Understanding rolling update of Spilo pods - -The operator logs reasons for a rolling update with the `info` level and a diff -between the old and new StatefulSet specs with the `debug` level. To benefit -from numerous escape characters in the latter log entry, view it in CLI with -`echo -e`. Note that the resultant message will contain some noise because the -`PodTemplate` used by the operator is yet to be updated with the default values -used internally in K8s. - -The operator also support lazy updates of the Spilo image. That means the pod -template of a PG cluster's stateful set is updated immediately with the new -image, but no rolling update follows. This feature saves you a switchover - and -hence downtime - when you know pods are re-started later anyway, for instance -due to the node rotation. To force a rolling update, disable this mode by -setting the `enable_lazy_spilo_upgrade` to `false` in the operator configuration -and restart the operator pod. With the standard eager rolling updates the -operator checks during Sync all pods run images specified in their respective -statefulsets. The operator triggers a rolling upgrade for PG clusters that -violate this condition. - -## Logical backups - -The operator can manage K8s cron jobs to run logical backups of Postgres -clusters. The cron job periodically spawns a batch job that runs a single pod. -The backup script within this pod's container can connect to a DB for a logical -backup. The operator updates cron jobs during Sync if the job schedule changes; -the job name acts as the job identifier. These jobs are to be enabled for each -individual Postgres cluster by setting `enableLogicalBackup: true` in its -manifest. Notes: - -1. The [example image](../docker/logical-backup/Dockerfile) implements the -backup via `pg_dumpall` and upload of compressed and encrypted results to an S3 -bucket; the default image ``registry.opensource.zalan.do/acid/logical-backup`` -is the same image built with the Zalando-internal CI pipeline. `pg_dumpall` -requires a `superuser` access to a DB and runs on the replica when possible. - -2. Due to the [limitation of K8s cron jobs](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-job-limitations) -it is highly advisable to set up additional monitoring for this feature; such -monitoring is outside of the scope of operator responsibilities. - -3. The operator does not remove old backups. - -4. You may use your own image by overwriting the relevant field in the operator -configuration. Any such image must ensure the logical backup is able to finish -[in presence of pod restarts](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#handling-pod-and-container-failures) -and [simultaneous invocations](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-job-limitations) -of the backup cron job. - -5. For that feature to work, your RBAC policy must enable operations on the -`cronjobs` resource from the `batch` API group for the operator service account. -See [example RBAC](../manifests/operator-service-account-rbac.yaml) - ## Access to cloud resources from clusters in non-cloud environment To access cloud resources like S3 from a cluster on bare metal you can use @@ -649,26 +618,127 @@ A secret can be pre-provisioned in different ways: * Automatically provisioned via a custom K8s controller like [kube-aws-iam-controller](https://github.com/mikkeloscar/kube-aws-iam-controller) -## Google Cloud Platform setup +## WAL archiving and physical basebackups -To configure the operator on GCP there are some prerequisites that are needed: +Spilo is shipped with [WAL-E](https://github.com/wal-e/wal-e) and its successor +[WAL-G](https://github.com/wal-g/wal-g) to perform WAL archiving. By default, +WAL-E is used for backups because it is more battle-tested. In addition to the +continuous backup stream WAL-E/G pushes a physical base backup every night and +01:00 am UTC. + +These are the pre-configured settings in the docker image: +```bash +BACKUP_NUM_TO_RETAIN: 5 +BACKUP_SCHEDULE: '00 01 * * *' +USE_WALG_BACKUP: false (true for Azure and SSH) +USE_WALG_RESTORE: false (true for S3, Azure and SSH) +``` + +Within Postgres you can check the pre-configured commands for archiving and +restoring WAL files. You can find the log files to the respective commands +under `$HOME/pgdata/pgroot/pg_log/postgres-?.log`. + +```bash +archive_command: `envdir "{WALE_ENV_DIR}" {WALE_BINARY} wal-push "%p"` +restore_command: `envdir "{{WALE_ENV_DIR}}" /scripts/restore_command.sh "%f" "%p"` +``` + +You can produce a basebackup manually with the following command and check +if it ends up in your specified WAL backup path: + +```bash +envdir "/run/etc/wal-e.d/env" /scripts/postgres_backup.sh "/home/postgres/pgdata/pgroot/data" +``` + +Depending on the cloud storage provider different [environment variables](https://github.com/zalando/spilo/blob/master/ENVIRONMENT.rst) +have to be set for Spilo. Not all of them are generated automatically by the +operator by changing its configuration. In this case you have to use an +[extra configmap or secret](#custom-pod-environment-variables). + +### Using AWS S3 or compliant services + +When using AWS you have to reference the S3 backup path, the IAM role and the +AWS region in the configuration. + +**postgres-operator ConfigMap** + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgres-operator +data: + aws_region: eu-central-1 + kube_iam_role: postgres-pod-role + wal_s3_bucket: your-backup-path +``` + +**OperatorConfiguration** + +```yaml +apiVersion: "acid.zalan.do/v1" +kind: OperatorConfiguration +metadata: + name: postgresql-operator-configuration +configuration: + aws_or_gcp: + aws_region: eu-central-1 + kube_iam_role: postgres-pod-role + wal_s3_bucket: your-backup-path +``` + +The referenced IAM role should contain the following privileges to make sure +Postgres can send compressed WAL files to the given S3 bucket: + +```yaml + PostgresPodRole: + Type: "AWS::IAM::Role" + Properties: + RoleName: "postgres-pod-role" + Path: "/" + Policies: + - PolicyName: "SpiloS3Access" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Action: "s3:*" + Effect: "Allow" + Resource: + - "arn:aws:s3:::your-backup-path" + - "arn:aws:s3:::your-backup-path/*" +``` + +This should produce the following settings for the essential environment +variables: + +```bash +AWS_ENDPOINT='https://s3.eu-central-1.amazonaws.com:443' +WALE_S3_ENDPOINT='https+path://s3.eu-central-1.amazonaws.com:443' +WALE_S3_PREFIX=$WAL_S3_BUCKET/spilo/{WAL_BUCKET_SCOPE_PREFIX}{SCOPE}{WAL_BUCKET_SCOPE_SUFFIX}/wal/{PGVERSION} +``` + +If the prefix is not specified Spilo will generate it from `WAL_S3_BUCKET`. +When the `AWS_REGION` is set `AWS_ENDPOINT` and `WALE_S3_ENDPOINT` are +generated automatically. `WALG_S3_PREFIX` is identical to `WALE_S3_PREFIX`. +`SCOPE` is the Postgres cluster name. + +### Google Cloud Platform setup + +To configure the operator on GCP these prerequisites that are needed: * A service account with the proper IAM setup to access the GCS bucket for the WAL-E logs * The credentials file for the service account. -The configuration paramaters that we will be using are: +The configuration parameters that we will be using are: * `additional_secret_mount` * `additional_secret_mount_path` * `gcp_credentials` * `wal_gs_bucket` -### Generate a K8s secret resource - -Generate the K8s secret resource that will contain your service account's +1. Generate the K8s secret resource that will contain your service account's credentials. It's highly recommended to use a service account and limit its scope to just the WAL-E bucket. - ```yaml apiVersion: v1 kind: Secret @@ -681,11 +751,9 @@ stringData: ``` -### Setup your operator configuration values - -With the `psql-wale-creds` resource applied to your cluster, ensure that -the operator's configuration is set up like the following: - +2. Setup your operator configuration values. With the `psql-wale-creds` +resource applied to your cluster, ensure that the operator's configuration +is set up like the following: ```yml ... aws_or_gcp: @@ -700,9 +768,8 @@ aws_or_gcp: ... ``` -### Setup pod environment configmap - -To make postgres-operator work with GCS, use following configmap: +3. Setup pod environment configmap that instructs the operator to use WAL-G, +instead of WAL-E, for backup and restore. ```yml apiVersion: v1 kind: ConfigMap @@ -715,9 +782,8 @@ data: USE_WALG_RESTORE: "true" CLONE_USE_WALG_RESTORE: "true" ``` -This configmap will instruct operator to use WAL-G, instead of WAL-E, for backup and restore. -Then provide this configmap in postgres-operator settings: +4. Then provide this configmap in postgres-operator settings: ```yml ... # namespaced name of the ConfigMap with environment variables to populate on every pod @@ -725,6 +791,62 @@ pod_environment_configmap: "postgres-operator-system/pod-env-overrides" ... ``` +### Restoring physical backups + +If cluster members have to be (re)initialized restoring physical backups +happens automatically either from the backup location or by running +[pg_basebackup](https://www.postgresql.org/docs/13/app-pgbasebackup.html) +on one of the other running instances (preferably replicas if they do not lag +behind). You can test restoring backups by [cloning](user.md#how-to-clone-an-existing-postgresql-cluster) +clusters. + +## Logical backups + +The operator can manage K8s cron jobs to run logical backups (SQL dumps) of +Postgres clusters. The cron job periodically spawns a batch job that runs a +single pod. The backup script within this pod's container can connect to a DB +for a logical backup. The operator updates cron jobs during Sync if the job +schedule changes; the job name acts as the job identifier. These jobs are to +be enabled for each individual Postgres cluster by updating the manifest: + +```yaml +apiVersion: "acid.zalan.do/v1" +kind: postgresql +metadata: + name: demo-cluster +spec: + enableLogicalBackup: true +``` + +There a few things to consider when using logical backups: + +1. Logical backups should not be seen as a proper alternative to basebackups +and WAL archiving which are described above. At the moment, the operator cannot +restore logical backups automatically and you do not get point-in-time recovery +but only snapshots of your data. In its current state, see logical backups as a +way to quickly create SQL dumps that you can easily restore in an empty test +cluster. + +2. The [example image](../docker/logical-backup/Dockerfile) implements the backup +via `pg_dumpall` and upload of compressed and encrypted results to an S3 bucket. +`pg_dumpall` requires a `superuser` access to a DB and runs on the replica when +possible. + +3. Due to the [limitation of K8s cron jobs](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-job-limitations) +it is highly advisable to set up additional monitoring for this feature; such +monitoring is outside of the scope of operator responsibilities. + +4. The operator does not remove old backups. + +5. You may use your own image by overwriting the relevant field in the operator +configuration. Any such image must ensure the logical backup is able to finish +[in presence of pod restarts](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#handling-pod-and-container-failures) +and [simultaneous invocations](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/#cron-job-limitations) +of the backup cron job. + +6. For that feature to work, your RBAC policy must enable operations on the +`cronjobs` resource from the `batch` API group for the operator service account. +See [example RBAC](../manifests/operator-service-account-rbac.yaml) ## Sidecars for Postgres clusters @@ -739,6 +861,7 @@ configuration: name: global-sidecar ports: - containerPort: 80 + protocol: TCP volumeMounts: - mountPath: /custom-pgdata-mountpoint name: pgdata @@ -814,7 +937,7 @@ make docker # build in image in minikube docker env eval $(minikube docker-env) -docker build -t registry.opensource.zalan.do/acid/postgres-operator-ui:v1.3.0 . +docker build -t registry.opensource.zalan.do/acid/postgres-operator-ui:v1.6.1 . # apply UI manifests next to a running Postgres Operator kubectl apply -f manifests/ diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index 54d13ffc2..eb1d855b7 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -565,7 +565,7 @@ grouped under the `logical_backup` key. runs `pg_dumpall` on a replica if possible and uploads compressed results to an S3 bucket under the key `/spilo/pg_cluster_name/cluster_k8s_uuid/logical_backups`. The default image is the same image built with the Zalando-internal CI - pipeline. Default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.0" + pipeline. Default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.1" * **logical_backup_google_application_credentials** Specifies the path of the google cloud service account json file. Default is empty. diff --git a/docs/user.md b/docs/user.md index ec5941d9e..8ba649bdd 100644 --- a/docs/user.md +++ b/docs/user.md @@ -30,7 +30,7 @@ spec: databases: foo: zalando postgresql: - version: "12" + version: "13" ``` Once you cloned the Postgres Operator [repository](https://github.com/zalando/postgres-operator) @@ -509,6 +509,25 @@ spec: defaultUsers: true ``` +### Schema `search_path` for default roles + +The schema [`search_path`](https://www.postgresql.org/docs/13/ddl-schemas.html#DDL-SCHEMAS-PATH) +for each role will include the role name and the schemas, this role should have +access to. So `foo_bar_writer` does not have to schema-qualify tables from +schemas `foo_bar_writer, bar`, while `foo_writer` can look up `foo_writer` and +any schema listed under `schemas`. To register the default `public` schema in +the `search_path` (because some extensions are installed there) one has to add +the following (assuming no extra roles are desired only for the public schema): + +```yaml +spec: + preparedDatabases: + foo: + schemas: + public: + defaultRoles: false +``` + ### Database extensions Prepared databases also allow for creating Postgres extensions. They will be @@ -625,6 +644,10 @@ spec: - pci ``` +## In-place major version upgrade + +Starting with Spilo 13, operator supports in-place major version upgrade to a higher major version (e.g. from PG 10 to PG 12). To trigger the upgrade, simply increase the version in the manifest. It is your responsibility to test your applications against the new version before the upgrade; downgrading is not supported. The easiest way to do so is to try the upgrade on the cloned cluster first. For details of how Spilo does the upgrade [see here](https://github.com/zalando/spilo/pull/488), operator implementation is described [in the admin docs](administrator.md#minor-and-major-version-upgrade). + ## How to clone an existing PostgreSQL cluster You can spin up a new cluster as a clone of the existing one, using a `clone` @@ -636,10 +659,6 @@ section in the spec. There are two options here: Note, that cloning can also be used for [major version upgrades](administrator.md#minor-and-major-version-upgrade) of PostgreSQL. -## In-place major version upgrade - -Starting with Spilo 13, operator supports in-place major version upgrade to a higher major version (e.g. from PG 10 to PG 12). To trigger the upgrade, simply increase the version in the manifest. It is your responsibility to test your applications against the new version before the upgrade; downgrading is not supported. The easiest way to do so is to try the upgrade on the cloned cluster first. For details of how Spilo does the upgrade [see here](https://github.com/zalando/spilo/pull/488), operator implementation is described [in the admin docs](administrator.md#minor-and-major-version-upgrade). - ### Clone from S3 Cloning from S3 has the advantage that there is no impact on your production @@ -687,7 +706,8 @@ spec: ### Clone directly -Another way to get a fresh copy of your source DB cluster is via basebackup. To +Another way to get a fresh copy of your source DB cluster is via +[pg_basebackup](https://www.postgresql.org/docs/13/app-pgbasebackup.html). To use this feature simply leave out the timestamp field from the clone section. The operator will connect to the service of the source cluster by name. If the cluster is called test, then the connection string will look like host=test @@ -875,8 +895,8 @@ size of volumes that correspond to the previously running pods is not changed. ## Logical backups -You can enable logical backups from the cluster manifest by adding the following -parameter in the spec section: +You can enable logical backups (SQL dumps) from the cluster manifest by adding +the following parameter in the spec section: ```yaml spec: diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index 9f2d19639..7f7b34d98 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -9,7 +9,7 @@ metadata: # "delete-date": "2020-08-31" # can only be deleted on that day if "delete-date "key is configured # "delete-clustername": "acid-test-cluster" # can only be deleted when name matches if "delete-clustername" key is configured spec: - dockerImage: registry.opensource.zalan.do/acid/spilo-13:2.0-p2 + dockerImage: registry.opensource.zalan.do/acid/spilo-13:2.0-p4 teamId: "acid" numberOfInstances: 2 users: # Application/Robot users @@ -148,18 +148,22 @@ spec: image: busybox command: [ "/bin/date" ] # 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" +# - name: "telegraf-sidecar" +# image: "telegraf:latest" +# ports: +# name: metrics +# containerPort: 8094 +# protocol: TCP +# resources: +# limits: +# cpu: 500m +# memory: 500Mi +# requests: +# cpu: 100m +# memory: 100Mi +# env: +# - name: "USEFUL_VAR" +# value: "perhaps-true" # Custom TLS certificate. Disabled unless tls.secretName has a value. tls: diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index f1bde6811..c35344b4d 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -16,7 +16,7 @@ data: # connection_pooler_default_cpu_request: "500m" # connection_pooler_default_memory_limit: 100Mi # connection_pooler_default_memory_request: 100Mi - connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-12" + connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-14" # connection_pooler_max_db_connections: 60 # connection_pooler_mode: "transaction" # connection_pooler_number_of_instances: 2 @@ -32,7 +32,7 @@ data: # default_memory_request: 100Mi # delete_annotation_date_key: delete-date # delete_annotation_name_key: delete-clustername - docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p2 + docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p4 # downscaler_annotations: "deployment-time,downscaler/*" # enable_admin_role_for_users: "true" # enable_crd_validation: "true" @@ -63,7 +63,7 @@ data: # inherited_labels: application,environment # kube_iam_role: "" # log_s3_bucket: "" - logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.0" + logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.1" # logical_backup_google_application_credentials: "" logical_backup_job_prefix: "logical-backup-" logical_backup_provider: "s3" @@ -125,4 +125,4 @@ data: # wal_gs_bucket: "" # wal_s3_bucket: "" watched_namespace: "*" # listen to all namespaces - workers: "16" + workers: "8" diff --git a/manifests/minimal-fake-pooler-deployment.yaml b/manifests/minimal-fake-pooler-deployment.yaml index 5ee8cf05f..823b4f24d 100644 --- a/manifests/minimal-fake-pooler-deployment.yaml +++ b/manifests/minimal-fake-pooler-deployment.yaml @@ -23,7 +23,7 @@ spec: serviceAccountName: postgres-operator containers: - name: postgres-operator - image: registry.opensource.zalan.do/acid/pgbouncer:master-12 + image: registry.opensource.zalan.do/acid/pgbouncer:master-14 imagePullPolicy: IfNotPresent resources: requests: diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index 7388a765b..227ce6689 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -61,7 +61,7 @@ spec: properties: docker_image: type: string - default: "registry.opensource.zalan.do/acid/spilo-13:2.0-p2" + default: "registry.opensource.zalan.do/acid/spilo-13:2.0-p4" enable_crd_validation: type: boolean default: true @@ -378,7 +378,7 @@ spec: properties: logical_backup_docker_image: type: string - default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.0" + default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.1" logical_backup_google_application_credentials: type: string logical_backup_job_prefix: @@ -507,7 +507,7 @@ spec: default: "pooler" connection_pooler_image: type: string - default: "registry.opensource.zalan.do/acid/pgbouncer:master-12" + default: "registry.opensource.zalan.do/acid/pgbouncer:master-14" connection_pooler_max_db_connections: type: integer default: 60 diff --git a/manifests/postgres-operator.yaml b/manifests/postgres-operator.yaml index a03959805..5c134345b 100644 --- a/manifests/postgres-operator.yaml +++ b/manifests/postgres-operator.yaml @@ -19,7 +19,7 @@ spec: serviceAccountName: postgres-operator containers: - name: postgres-operator - image: registry.opensource.zalan.do/acid/postgres-operator:v1.6.0 + image: registry.opensource.zalan.do/acid/postgres-operator:v1.6.1 imagePullPolicy: IfNotPresent resources: requests: diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index 18680fbb0..0c0daa924 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -3,7 +3,7 @@ kind: OperatorConfiguration metadata: name: postgresql-operator-default-configuration configuration: - docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p2 + docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p4 # enable_crd_validation: true # enable_lazy_spilo_upgrade: false enable_pgversion_env_var: true @@ -21,6 +21,7 @@ configuration: # name: global-sidecar-1 # ports: # - containerPort: 80 + # protocol: TCP workers: 8 users: replication_username: standby @@ -117,7 +118,7 @@ configuration: # wal_gs_bucket: "" # wal_s3_bucket: "" logical_backup: - logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.0" + logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.1" # logical_backup_google_application_credentials: "" logical_backup_job_prefix: "logical-backup-" logical_backup_provider: "s3" @@ -156,7 +157,7 @@ configuration: connection_pooler_default_cpu_request: "500m" connection_pooler_default_memory_limit: 100Mi connection_pooler_default_memory_request: 100Mi - connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-9" + connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-14" # connection_pooler_max_db_connections: 60 connection_pooler_mode: "transaction" connection_pooler_number_of_instances: 2 diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 6ef7a2f42..dbdd4afb4 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -39,7 +39,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.EnableSpiloWalPathCompat = fromCRD.EnableSpiloWalPathCompat result.EtcdHost = fromCRD.EtcdHost result.KubernetesUseConfigMaps = fromCRD.KubernetesUseConfigMaps - result.DockerImage = util.Coalesce(fromCRD.DockerImage, "registry.opensource.zalan.do/acid/spilo-13:2.0-p2") + result.DockerImage = util.Coalesce(fromCRD.DockerImage, "registry.opensource.zalan.do/acid/spilo-13:2.0-p4") result.Workers = util.CoalesceUInt32(fromCRD.Workers, 8) result.MinInstances = fromCRD.MinInstances result.MaxInstances = fromCRD.MaxInstances @@ -146,7 +146,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur // logical backup config result.LogicalBackupSchedule = util.Coalesce(fromCRD.LogicalBackup.Schedule, "30 00 * * *") - result.LogicalBackupDockerImage = util.Coalesce(fromCRD.LogicalBackup.DockerImage, "registry.opensource.zalan.do/acid/logical-backup:v1.6.0") + result.LogicalBackupDockerImage = util.Coalesce(fromCRD.LogicalBackup.DockerImage, "registry.opensource.zalan.do/acid/logical-backup:v1.6.1") result.LogicalBackupProvider = util.Coalesce(fromCRD.LogicalBackup.BackupProvider, "s3") result.LogicalBackupS3Bucket = fromCRD.LogicalBackup.S3Bucket result.LogicalBackupS3Region = fromCRD.LogicalBackup.S3Region diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 4f4940567..93fceff01 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -113,7 +113,7 @@ type Scalyr struct { // 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:v1.6.0"` + LogicalBackupDockerImage string `name:"logical_backup_docker_image" default:"registry.opensource.zalan.do/acid/logical-backup:v1.6.1"` LogicalBackupProvider string `name:"logical_backup_provider" default:"s3"` LogicalBackupS3Bucket string `name:"logical_backup_s3_bucket" default:""` LogicalBackupS3Region string `name:"logical_backup_s3_region" default:""` @@ -151,7 +151,7 @@ type Config struct { WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to' KubernetesUseConfigMaps bool `name:"kubernetes_use_configmaps" default:"false"` EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS - DockerImage string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spilo-13:2.0-p2"` + DockerImage string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spilo-13:2.0-p4"` SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers SidecarContainers []v1.Container `name:"sidecars"` PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"`