Merge branch 'master' into feature/adjust-per-pool-values
This commit is contained in:
commit
39c29d45fe
|
|
@ -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.3
|
||||
- **Which image of the operator are you using?** e.g. ghcr.io/zalando/postgres-operator:v1.15.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.]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
name: Publish multiarch postgres-operator images on ghcr.io
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
IMAGE_NAME_UI: ${{ github.repository }}-ui
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Build, test and push image
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.26.4"
|
||||
|
||||
- name: Run unit tests
|
||||
run: make test
|
||||
|
||||
- name: Define image name
|
||||
id: image
|
||||
run: |
|
||||
OPERATOR_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF/refs\/tags\//}"
|
||||
echo "OPERATOR_IMAGE=$OPERATOR_IMAGE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Define pooler image name
|
||||
id: image_pooler
|
||||
run: |
|
||||
POOLER_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/pgbouncer:${GITHUB_REF/refs\/tags\//}"
|
||||
echo "POOLER_IMAGE=$POOLER_IMAGE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Define UI image name
|
||||
id: image_ui
|
||||
run: |
|
||||
UI_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME_UI }}:${GITHUB_REF/refs\/tags\//}"
|
||||
echo "UI_IMAGE=$UI_IMAGE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Define logical backup image name
|
||||
id: image_lb
|
||||
run: |
|
||||
BACKUP_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/logical-backup:${GITHUB_REF_NAME}"
|
||||
echo "BACKUP_IMAGE=$BACKUP_IMAGE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push multiarch operator image to ghcr
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: true
|
||||
build-args: BASE_IMAGE=alpine:3
|
||||
tags: "${{ steps.image.outputs.OPERATOR_IMAGE }}"
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Build and push multiarch pooler image to ghcr
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: pooler
|
||||
push: true
|
||||
build-args: BASE_IMAGE=alpine:3.22
|
||||
tags: "${{ steps.image_pooler.outputs.POOLER_IMAGE }}"
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Build and push multiarch ui image to ghcr
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: ui
|
||||
push: true
|
||||
build-args: BASE_IMAGE=python:3.11-slim
|
||||
tags: "${{ steps.image_ui.outputs.UI_IMAGE }}"
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Build and push multiarch logical-backup image to ghcr
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: logical-backup
|
||||
push: true
|
||||
build-args: BASE_IMAGE=ubuntu:22.04
|
||||
tags: "${{ steps.image_lb.outputs.BACKUP_IMAGE }}"
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Build and push postgres-operator chart to ghcr
|
||||
run: |
|
||||
helm package charts/postgres-operator
|
||||
helm push postgres-operator-*.tgz oci://${{ env.REGISTRY }}/zalando/charts
|
||||
rm -rf postgres-operator-*.tgz
|
||||
|
||||
- name: Build and push postgres-operator-ui chart to ghcr
|
||||
run: |
|
||||
helm package charts/postgres-operator-ui
|
||||
helm push postgres-operator-ui-*.tgz oci://${{ env.REGISTRY }}/zalando/charts
|
||||
rm -rf postgres-operator-ui-*.tgz
|
||||
|
|
@ -11,15 +11,15 @@ jobs:
|
|||
name: End-2-End tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-go@v2
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.15.6"
|
||||
go-version: "^1.26.4"
|
||||
- name: Make dependencies
|
||||
run: make deps mocks
|
||||
- name: Compile
|
||||
run: make linux
|
||||
run: make mocks
|
||||
- name: Code generation
|
||||
run: make codegen
|
||||
- name: Run unit tests
|
||||
run: go test ./...
|
||||
run: make test
|
||||
- name: Run end-2-end tests
|
||||
run: make e2e
|
||||
|
|
|
|||
|
|
@ -11,18 +11,18 @@ jobs:
|
|||
name: Unit tests and coverage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.15.6"
|
||||
go-version: "^1.26.4"
|
||||
- name: Make dependencies
|
||||
run: make deps mocks
|
||||
run: make mocks
|
||||
- name: Compile
|
||||
run: make linux
|
||||
- name: Run unit tests
|
||||
run: go test -race -covermode atomic -coverprofile=coverage.out ./...
|
||||
- name: Convert coverage to lcov
|
||||
uses: jandelgado/gcov2lcov-action@v1.0.8
|
||||
uses: jandelgado/gcov2lcov-action@v1.1.1
|
||||
- name: Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -94,9 +94,14 @@ coverage.xml
|
|||
|
||||
# e2e tests
|
||||
e2e/manifests
|
||||
e2e/tls
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
mocks
|
||||
|
||||
ui/.npm/
|
||||
|
||||
.DS_Store
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
# global owners
|
||||
* @erthalion @sdudoladov @Jan-M @CyberDem0n @avaczi @FxKu @RafiaSabih
|
||||
* @sdudoladov @Jan-M @FxKu @jopadi @idanovinda @hughcapet @mikkeloscar
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 Zalando SE
|
||||
Copyright (c) 2026 Zalando SE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
Dmitrii Dolgov <dmitrii.dolgov@zalando.de>
|
||||
Sergey Dudoladov <sergey.dudoladov@zalando.de>
|
||||
Felix Kunde <felix.kunde@zalando.de>
|
||||
Jan Mussler <jan.mussler@zalando.de>
|
||||
Rafia Sabih <rafia.sabih@zalando.de>
|
||||
Jociele Padilha <jociele.padilha@zalando.de>
|
||||
Ida Novindasari <ida.novindasari@zalando.de>
|
||||
Polina Bungina <polina.bungina@zalando.de>
|
||||
Mikkel Larsen <mikkel.larsen@zalando.de>
|
||||
|
|
|
|||
85
Makefile
85
Makefile
|
|
@ -1,7 +1,8 @@
|
|||
.PHONY: clean local test linux macos mocks docker push scm-source.json e2e
|
||||
.PHONY: clean local test linux macos mocks docker pooler push e2e
|
||||
|
||||
BINARY ?= postgres-operator
|
||||
BUILD_FLAGS ?= -v
|
||||
GOARCH ?= amd64
|
||||
CGO_ENABLED ?= 0
|
||||
ifeq ($(RACE),1)
|
||||
BUILD_FLAGS += -race -a
|
||||
|
|
@ -12,13 +13,17 @@ LOCAL_BUILD_FLAGS ?= $(BUILD_FLAGS)
|
|||
LDFLAGS ?= -X=main.version=$(VERSION)
|
||||
DOCKERDIR = docker
|
||||
|
||||
IMAGE ?= registry.opensource.zalan.do/acid/$(BINARY)
|
||||
BASE_IMAGE ?= alpine:latest
|
||||
IMAGE ?= ghcr.io/zalando/$(BINARY)
|
||||
TAG ?= $(VERSION)
|
||||
GITHEAD = $(shell git rev-parse --short HEAD)
|
||||
GITURL = $(shell git config --get remote.origin.url)
|
||||
GITSTATUS = $(shell git status --porcelain || echo "no changes")
|
||||
SOURCES = cmd/main.go
|
||||
VERSION ?= $(shell git describe --tags --always --dirty)
|
||||
CRD_SOURCES = $(shell find pkg/apis/zalando.org pkg/apis/acid.zalan.do -name '*.go' -not -name '*.deepcopy.go')
|
||||
GENERATED_CRDS = manifests/postgresteam.crd.yaml manifests/postgresql.crd.yaml pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml
|
||||
GENERATED = pkg/apis/zalando.org/v1/zz_generated.deepcopy.go pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go
|
||||
DIRS := cmd pkg
|
||||
PKG := `go list ./... | grep -v /vendor/`
|
||||
|
||||
|
|
@ -42,52 +47,64 @@ ifndef GOPATH
|
|||
GOPATH := $(HOME)/go
|
||||
endif
|
||||
|
||||
PATH := $(GOPATH)/bin:$(PATH)
|
||||
SHELL := env PATH=$(PATH) $(SHELL)
|
||||
PATH := $(GOPATH)/bin:$(PATH)
|
||||
SHELL := env PATH="$(PATH)" $(SHELL)
|
||||
IMAGE_TAG := $(IMAGE):$(TAG)$(CDP_TAG)$(DEBUG_FRESH)$(DEBUG_POSTFIX)
|
||||
POOLER_TAG := $(IMAGE)/pgbouncer:$(TAG)$(CDP_TAG)$(DEBUG_FRESH)$(DEBUG_POSTFIX)
|
||||
|
||||
default: local
|
||||
|
||||
clean:
|
||||
rm -rf build scm-source.json
|
||||
rm -rf build
|
||||
rm $(GENERATED)
|
||||
rm $(GENERATED_CRDS)
|
||||
|
||||
local: ${SOURCES}
|
||||
verify:
|
||||
hack/verify-codegen.sh
|
||||
CGO_ENABLED=${CGO_ENABLED} go build -o build/${BINARY} $(LOCAL_BUILD_FLAGS) -ldflags "$(LDFLAGS)" $^
|
||||
|
||||
linux: ${SOURCES}
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} go build -o build/linux/${BINARY} ${BUILD_FLAGS} -ldflags "$(LDFLAGS)" $^
|
||||
$(GENERATED): go.mod $(CRD_SOURCES)
|
||||
hack/update-codegen.sh
|
||||
|
||||
macos: ${SOURCES}
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} go build -o build/macos/${BINARY} ${BUILD_FLAGS} -ldflags "$(LDFLAGS)" $^
|
||||
$(GENERATED_CRDS): $(GENERATED)
|
||||
go tool controller-gen crd:crdVersions=v1,allowDangerousTypes=true paths=./pkg/apis/acid.zalan.do/... output:crd:dir=manifests
|
||||
@mv manifests/acid.zalan.do_postgresqls.yaml manifests/postgresql.crd.yaml
|
||||
@# hack to use lowercase kind and listKind
|
||||
@sed -i -e 's/kind: Postgresql/kind: postgresql/' manifests/postgresql.crd.yaml
|
||||
@sed -i -e 's/listKind: PostgresqlList/listKind: postgresqlList/' manifests/postgresql.crd.yaml
|
||||
@hack/adjust_postgresql_crd.sh
|
||||
@mv manifests/acid.zalan.do_operatorconfigurations.yaml manifests/operatorconfiguration.crd.yaml
|
||||
@mv manifests/acid.zalan.do_postgresteams.yaml manifests/postgresteam.crd.yaml
|
||||
@cp manifests/postgresql.crd.yaml pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml
|
||||
@cp manifests/operatorconfiguration.crd.yaml pkg/apis/acid.zalan.do/v1/operatorconfiguration.crd.yaml
|
||||
|
||||
docker-context: scm-source.json linux
|
||||
mkdir -p docker/build/
|
||||
cp build/linux/${BINARY} scm-source.json docker/build/
|
||||
local: ${SOURCES} $(GENERATED_CRDS)
|
||||
CGO_ENABLED=${CGO_ENABLED} go build -o build/${BINARY} $(LOCAL_BUILD_FLAGS) -ldflags "$(LDFLAGS)" $(SOURCES)
|
||||
|
||||
docker: ${DOCKERDIR}/${DOCKERFILE} docker-context
|
||||
wasm: ${SOURCES} $(GENERATED_CRDS)
|
||||
GOOS=wasip1 GOARCH=wasm CGO_ENABLED=${CGO_ENABLED} go build -o build/${BINARY}.wasm ${BUILD_FLAGS} -ldflags "$(LDFLAGS)" $(SOURCES)
|
||||
|
||||
linux: ${SOURCES} $(GENERATED_CRDS)
|
||||
GOOS=linux GOARCH=${GOARCH} CGO_ENABLED=${CGO_ENABLED} go build -o build/linux/${BINARY} ${BUILD_FLAGS} -ldflags "$(LDFLAGS)" $(SOURCES)
|
||||
|
||||
macos: ${SOURCES} $(GENERATED_CRDS)
|
||||
GOOS=darwin GOARCH=${GOARCH} CGO_ENABLED=${CGO_ENABLED} go build -o build/macos/${BINARY} ${BUILD_FLAGS} -ldflags "$(LDFLAGS)" $(SOURCES)
|
||||
|
||||
docker: $(GENERATED_CRDS) ${DOCKERDIR}/${DOCKERFILE}
|
||||
echo `(env)`
|
||||
echo "Tag ${TAG}"
|
||||
echo "Version ${VERSION}"
|
||||
echo "CDP tag ${CDP_TAG}"
|
||||
echo "git describe $(shell git describe --tags --always --dirty)"
|
||||
cd "${DOCKERDIR}" && docker build --rm -t "$(IMAGE):$(TAG)$(CDP_TAG)$(DEBUG_FRESH)$(DEBUG_POSTFIX)" -f "${DOCKERFILE}" .
|
||||
docker build --rm -t "$(IMAGE_TAG)" -f "${DOCKERDIR}/${DOCKERFILE}" --build-arg VERSION="${VERSION}" --build-arg BASE_IMAGE="${BASE_IMAGE}" .
|
||||
|
||||
pooler:
|
||||
cd pooler; docker build --rm -t "$(POOLER_TAG)" --build-arg VERSION="${VERSION}" --build-arg BASE_IMAGE="${BASE_IMAGE}" .
|
||||
|
||||
indocker-race:
|
||||
docker run --rm -v "${GOPATH}":"${GOPATH}" -e GOPATH="${GOPATH}" -e RACE=1 -w ${PWD} golang:1.8.1 bash -c "make linux"
|
||||
|
||||
push:
|
||||
docker push "$(IMAGE):$(TAG)$(CDP_TAG)"
|
||||
|
||||
scm-source.json: .git
|
||||
echo '{\n "url": "git:$(GITURL)",\n "revision": "$(GITHEAD)",\n "author": "$(USER)",\n "status": "$(GITSTATUS)"\n}' > scm-source.json
|
||||
docker run --rm -v "${GOPATH}":"${GOPATH}" -e GOPATH="${GOPATH}" -e RACE=1 -w ${PWD} golang:1.26.4 bash -c "make linux"
|
||||
|
||||
mocks:
|
||||
GO111MODULE=on go generate ./...
|
||||
|
||||
tools:
|
||||
GO111MODULE=on go get k8s.io/client-go@kubernetes-1.20.6
|
||||
GO111MODULE=on go get github.com/golang/mock/mockgen@v1.4.4
|
||||
GO111MODULE=on go mod tidy
|
||||
go generate ./...
|
||||
|
||||
fmt:
|
||||
@gofmt -l -w -s $(DIRS)
|
||||
|
|
@ -96,12 +113,10 @@ vet:
|
|||
@go vet $(PKG)
|
||||
@staticcheck $(PKG)
|
||||
|
||||
deps: tools
|
||||
GO111MODULE=on go mod vendor
|
||||
test: mocks $(GENERATED) $(GENERATED_CRDS)
|
||||
go test ./...
|
||||
|
||||
test:
|
||||
hack/verify-codegen.sh
|
||||
GO111MODULE=on go test ./...
|
||||
codegen: $(GENERATED)
|
||||
|
||||
e2e: docker # build operator image to be tested
|
||||
e2e: docker pooler # build operator and pooler images to be tested
|
||||
cd e2e; make e2etest
|
||||
|
|
|
|||
63
README.md
63
README.md
|
|
@ -16,60 +16,60 @@ pipelines with no access to Kubernetes API directly, promoting infrastructure as
|
|||
* Rolling updates on Postgres cluster changes, incl. quick minor version updates
|
||||
* Live volume resize without pod restarts (AWS EBS, PVC)
|
||||
* Database connection pooling with PGBouncer
|
||||
* Support fast in place major version upgrade to PG13. Supports global upgrade of all clusters.
|
||||
* Restore and cloning Postgres clusters (incl. major version upgrade)
|
||||
* Additionally logical backups to S3 bucket can be configured
|
||||
* Standby cluster from S3 WAL archive
|
||||
* Support fast in place major version upgrade. Supports global upgrade of all clusters.
|
||||
* Pod protection during bootstrap phase and configurable maintenance windows
|
||||
* Restore and cloning Postgres clusters on AWS, GCS and Azure
|
||||
* Additionally logical backups to S3 or GCS bucket can be configured
|
||||
* Standby cluster from S3 or GCS WAL archive
|
||||
* Configurable for non-cloud environments
|
||||
* Basic credential and user management on K8s, eases application deployments
|
||||
* 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
|
||||
* Support for AWS EBS gp2 to gp3 migration, supporting iops and throughput configuration
|
||||
* Compatible with OpenShift
|
||||
|
||||
### PostgreSQL features
|
||||
|
||||
* Supports PostgreSQL 13, starting from 9.6+
|
||||
* Supports PostgreSQL 18, starting from 14+
|
||||
* Streaming replication cluster via Patroni
|
||||
* Point-In-Time-Recovery with
|
||||
[pg_basebackup](https://www.postgresql.org/docs/11/app-pgbasebackup.html) /
|
||||
[WAL-E](https://github.com/wal-e/wal-e) via [Spilo](https://github.com/zalando/spilo)
|
||||
[pg_basebackup](https://www.postgresql.org/docs/18/app-pgbasebackup.html) /
|
||||
[WAL-G](https://github.com/wal-g/wal-g) or [WAL-E](https://github.com/wal-e/wal-e) via [Spilo](https://github.com/zalando/spilo)
|
||||
* Preload libraries: [bg_mon](https://github.com/CyberDem0n/bg_mon),
|
||||
[pg_stat_statements](https://www.postgresql.org/docs/9.4/pgstatstatements.html),
|
||||
[pg_stat_statements](https://www.postgresql.org/docs/18/pgstatstatements.html),
|
||||
[pgextwlist](https://github.com/dimitri/pgextwlist),
|
||||
[pg_auth_mon](https://github.com/RafiaSabih/pg_auth_mon)
|
||||
* Incl. popular Postgres extensions such as
|
||||
[decoderbufs](https://github.com/debezium/postgres-decoderbufs),
|
||||
[hypopg](https://github.com/HypoPG/hypopg),
|
||||
[pg_cron](https://github.com/citusdata/pg_cron),
|
||||
[pg_repack](https://github.com/reorg/pg_repack),
|
||||
[pg_partman](https://github.com/pgpartman/pg_partman),
|
||||
[pg_stat_kcache](https://github.com/powa-team/pg_stat_kcache),
|
||||
[pg_audit](https://github.com/pgaudit/pgaudit),
|
||||
[pgfaceting](https://github.com/cybertec-postgresql/pgfaceting),
|
||||
[pgq](https://github.com/pgq/pgq),
|
||||
[pgvector](https://github.com/pgvector/pgvector),
|
||||
[plpgsql_check](https://github.com/okbob/plpgsql_check),
|
||||
[plproxy](https://github.com/plproxy/plproxy),
|
||||
[postgis](https://postgis.net/),
|
||||
[roaringbitmap](https://github.com/ChenHuajun/pg_roaringbitmap),
|
||||
[set_user](https://github.com/pgaudit/set_user) and
|
||||
[timescaledb](https://github.com/timescale/timescaledb)
|
||||
|
||||
The Postgres Operator has been developed at Zalando and is being used in
|
||||
production for over three years.
|
||||
production for over five years.
|
||||
|
||||
## Notes on Postgres 13 support
|
||||
|
||||
If you are new to the operator, you can skip this and just start using the Postgres operator as is, Postgres 13 is ready to go.
|
||||
|
||||
The Postgres operator supports Postgres 13 with the new Spilo Image that includes also the recent Patroni version to support PG13 settings.
|
||||
More work on optimizing restarts and rolling upgrades is pending.
|
||||
|
||||
If you are already using the Postgres operator in older version with a Spilo 12 Docker image you need to be aware of the changes for the backup path.
|
||||
We introduce the major version into the backup path to smoothen the [major version upgrade](docs/administrator.md#minor-and-major-version-upgrade) that is now supported manually.
|
||||
|
||||
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 newest Spilo 13 image is: `registry.opensource.zalan.do/acid/spilo-13:2.0-p7`
|
||||
|
||||
The last Spilo 12 image is: `registry.opensource.zalan.do/acid/spilo-12:1.6-p5`
|
||||
## Supported Postgres & K8s versions
|
||||
|
||||
| Release | Postgres versions | K8s versions | Golang |
|
||||
| :-------- | :---------------: | :---------------: | :-----: |
|
||||
| next | 14 → 18 | 1.27+ | 1.26.4 |
|
||||
| v1.15.1 | 13 → 17 | 1.27+ | 1.25.3 |
|
||||
| v1.14.0 | 13 → 17 | 1.27+ | 1.23.4 |
|
||||
| v1.13.0 | 12 → 16 | 1.27+ | 1.22.5 |
|
||||
| v1.12.0 | 11 → 16 | 1.27+ | 1.22.3 |
|
||||
| v1.11.0 | 11 → 16 | 1.27+ | 1.21.7 |
|
||||
| v1.10.1 | 10 → 15 | 1.21+ | 1.19.8 |
|
||||
|
||||
## Getting started
|
||||
|
||||
|
|
@ -78,7 +78,8 @@ For a quick first impression follow the instructions of this
|
|||
|
||||
## Supported setups of Postgres and Applications
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
@ -94,9 +95,3 @@ There is a browser-friendly version of this documentation at
|
|||
* [Configuration options](docs/reference/operator_parameters.md)
|
||||
* [Postgres manifest reference](docs/reference/cluster_manifest.md)
|
||||
* [Command-line options and environment variables](docs/reference/command_line_and_environment.md)
|
||||
|
||||
## Community
|
||||
|
||||
There are two places to get in touch with the community:
|
||||
1. The [GitHub issue tracker](https://github.com/zalando/postgres-operator/issues)
|
||||
2. The **#postgres-operator** [slack channel](https://postgres-slack.herokuapp.com)
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ mkdir -p "$team_repo"
|
|||
ln -s "$PWD" "$project_dir"
|
||||
cd "$project_dir"
|
||||
|
||||
make deps clean docker push
|
||||
make clean docker push
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: v1
|
||||
apiVersion: v2
|
||||
name: postgres-operator-ui
|
||||
version: 1.6.3
|
||||
appVersion: 1.6.3
|
||||
version: 1.15.1
|
||||
appVersion: 1.15.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:
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
apiVersion: v1
|
||||
entries:
|
||||
postgres-operator-ui:
|
||||
- apiVersion: v1
|
||||
appVersion: 1.6.3
|
||||
created: "2021-05-27T19:04:33.425637932+02:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
||||
digest: 08b810aa632dcc719e4785ef184e391267f7c460caa99677f2d00719075aac78
|
||||
- apiVersion: v2
|
||||
appVersion: 1.15.1
|
||||
created: "2025-12-11T12:44:25.470723322+01:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||
database-as-a-service user experience
|
||||
digest: 4bbb750934366038d692711f924151182b7be131b6822d011f5a4e51cf609482
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -21,13 +22,14 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-ui-1.6.3.tgz
|
||||
version: 1.6.3
|
||||
- apiVersion: v1
|
||||
appVersion: 1.6.2
|
||||
created: "2021-05-27T19:04:33.422124263+02:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
||||
digest: 14d1559bb0bd1e1e828f2daaaa6f6ac9ffc268d79824592c3589b55dd39241f6
|
||||
- postgres-operator-ui-1.15.1.tgz
|
||||
version: 1.15.1
|
||||
- apiVersion: v2
|
||||
appVersion: 1.14.0
|
||||
created: "2025-12-11T12:44:25.468680645+01:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||
database-as-a-service user experience
|
||||
digest: e87ed898079a852957a67a4caf3fbd27b9098e413f5d961b7a771a6ae8b3e17c
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -43,13 +45,14 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-ui-1.6.2.tgz
|
||||
version: 1.6.2
|
||||
- apiVersion: v1
|
||||
appVersion: 1.6.1
|
||||
created: "2021-05-27T19:04:33.419640902+02:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
||||
digest: 3d321352f2f1e7bb7450aa8876e3d818aa9f9da9bd4250507386f0490f2c1969
|
||||
- postgres-operator-ui-1.14.0.tgz
|
||||
version: 1.14.0
|
||||
- apiVersion: v2
|
||||
appVersion: 1.13.0
|
||||
created: "2025-12-11T12:44:25.466716836+01:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||
database-as-a-service user experience
|
||||
digest: e0444e516b50f82002d1a733527813c51759a627cefdd1005cea73659f824ea8
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -65,13 +68,14 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-ui-1.6.1.tgz
|
||||
version: 1.6.1
|
||||
- apiVersion: v1
|
||||
appVersion: 1.6.0
|
||||
created: "2021-05-27T19:04:33.41788193+02:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
||||
digest: 1e0aa1e7db3c1daa96927ffbf6fdbcdb434562f961833cb5241ddbe132220ee4
|
||||
- postgres-operator-ui-1.13.0.tgz
|
||||
version: 1.13.0
|
||||
- apiVersion: v2
|
||||
appVersion: 1.12.2
|
||||
created: "2025-12-11T12:44:25.464739895+01:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||
database-as-a-service user experience
|
||||
digest: cbcef400c23ccece27d97369ad629278265c013e0a45c0b7f33e7568a082fedd
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -87,13 +91,14 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-ui-1.6.0.tgz
|
||||
version: 1.6.0
|
||||
- apiVersion: v1
|
||||
appVersion: 1.5.0
|
||||
created: "2021-05-27T19:04:33.416056821+02:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
||||
digest: c91ea39e6d51d57f4048fb1b6ec53b40823f2690eb88e4e4f1a036367b9fdd61
|
||||
- postgres-operator-ui-1.12.2.tgz
|
||||
version: 1.12.2
|
||||
- apiVersion: v2
|
||||
appVersion: 1.11.0
|
||||
created: "2025-12-11T12:44:25.462698399+01:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||
database-as-a-service user experience
|
||||
digest: a45f2284045c2a9a79750a36997386444f39b01ac722b17c84b431457577a3a2
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -109,6 +114,29 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-ui-1.5.0.tgz
|
||||
version: 1.5.0
|
||||
generated: "2021-05-27T19:04:33.41380858+02:00"
|
||||
- postgres-operator-ui-1.11.0.tgz
|
||||
version: 1.11.0
|
||||
- apiVersion: v2
|
||||
appVersion: 1.10.1
|
||||
created: "2025-12-11T12:44:25.460357063+01:00"
|
||||
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||
database-as-a-service user experience
|
||||
digest: 2e5e7a82aebee519ec57c6243eb8735124aa4585a3a19c66ffd69638fbeb11ce
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
- operator
|
||||
- ui
|
||||
- cloud-native
|
||||
- patroni
|
||||
- spilo
|
||||
maintainers:
|
||||
- email: opensource@zalando.de
|
||||
name: Zalando
|
||||
name: postgres-operator-ui
|
||||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-ui-1.10.1.tgz
|
||||
version: 1.10.1
|
||||
generated: "2025-12-11T12:44:25.45732896+01:00"
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -7,8 +7,9 @@ metadata:
|
|||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ template "postgres-operator-ui.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
replicas: 1
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
|
||||
|
|
@ -18,6 +19,10 @@ spec:
|
|||
labels:
|
||||
app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
serviceAccountName: {{ include "postgres-operator-ui.serviceAccountName" . }}
|
||||
{{- if .Values.imagePullSecrets }}
|
||||
|
|
@ -41,7 +46,7 @@ spec:
|
|||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
env:
|
||||
- name: "APP_URL"
|
||||
value: "http://localhost:8081"
|
||||
value: {{ .Values.envs.appUrl }}
|
||||
- name: "OPERATOR_API_URL"
|
||||
value: {{ .Values.envs.operatorApiUrl | quote }}
|
||||
- name: "OPERATOR_CLUSTER_NAME_LABEL"
|
||||
|
|
@ -62,16 +67,39 @@ spec:
|
|||
value: |-
|
||||
{
|
||||
"docs_link":"https://postgres-operator.readthedocs.io/en/latest/",
|
||||
"dns_format_string": "{1}-{0}.{2}",
|
||||
"dns_format_string": "{0}.{1}",
|
||||
"databases_visible": true,
|
||||
"master_load_balancer_visible": true,
|
||||
"nat_gateways_visible": false,
|
||||
"replica_load_balancer_visible": true,
|
||||
"resources_visible": true,
|
||||
"users_visible": true,
|
||||
"cost_ebs": 0.0952,
|
||||
"cost_iops": 0.006,
|
||||
"cost_throughput": 0.0476,
|
||||
"cost_core": 0.0575,
|
||||
"cost_memory": 0.014375,
|
||||
"free_iops": 3000,
|
||||
"free_throughput": 125,
|
||||
"limit_iops": 16000,
|
||||
"limit_throughput": 1000,
|
||||
"postgresql_versions": [
|
||||
"13",
|
||||
"12",
|
||||
"11"
|
||||
"18",
|
||||
"17",
|
||||
"16",
|
||||
"15",
|
||||
"14",
|
||||
]
|
||||
}
|
||||
{{- if .Values.extraEnvs }}
|
||||
{{- .Values.extraEnvs | toYaml | nindent 12 }}
|
||||
{{- end }}
|
||||
affinity:
|
||||
{{ toYaml .Values.affinity | indent 8 }}
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.nodeSelector | indent 8 }}
|
||||
tolerations:
|
||||
{{ toYaml .Values.tolerations | indent 8 }}
|
||||
{{- if .Values.priorityClassName }}
|
||||
priorityClassName: {{ .Values.priorityClassName }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "postgres-operator-ui.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
|
||||
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
|
|
@ -9,6 +12,7 @@ apiVersion: extensions/v1beta1
|
|||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
|
||||
helm.sh/chart: {{ template "postgres-operator-ui.chart" . }}
|
||||
|
|
@ -19,6 +23,9 @@ metadata:
|
|||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.ingressClassName }}
|
||||
ingressClassName: {{ .Values.ingress.ingressClassName }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
|
|
@ -36,9 +43,18 @@ spec:
|
|||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ . }}
|
||||
{{ if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion -}}
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ $fullName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- else -}}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $svcPort }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ metadata:
|
|||
helm.sh/chart: {{ template "postgres-operator-ui.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- with .Values.service.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
name: {{ template "postgres-operator-ui.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ apiVersion: v1
|
|||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "postgres-operator-ui.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
|
||||
helm.sh/chart: {{ template "postgres-operator-ui.chart" . }}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ replicaCount: 1
|
|||
|
||||
# configure ui image
|
||||
image:
|
||||
registry: registry.opensource.zalan.do
|
||||
repository: acid/postgres-operator-ui
|
||||
tag: v1.6.3
|
||||
registry: ghcr.io
|
||||
repository: zalando/postgres-operator-ui
|
||||
tag: v1.15.1
|
||||
pullPolicy: "IfNotPresent"
|
||||
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
|
|
@ -39,15 +39,49 @@ resources:
|
|||
|
||||
# configure UI ENVs
|
||||
envs:
|
||||
# IMPORTANT: While operator chart and UI chart are idendependent, this is the interface between
|
||||
# IMPORTANT: While operator chart and UI chart are independent, this is the interface between
|
||||
# UI and operator API. Insert the service name of the operator API here!
|
||||
appUrl: "http://localhost:8081"
|
||||
operatorApiUrl: "http://postgres-operator:8080"
|
||||
operatorClusterNameLabel: "cluster-name"
|
||||
resourcesVisible: "False"
|
||||
# Set to "*" to allow viewing/creation of clusters in all namespaces
|
||||
targetNamespace: "default"
|
||||
teams:
|
||||
- "acid"
|
||||
|
||||
# Extra pod annotations
|
||||
podAnnotations:
|
||||
{}
|
||||
|
||||
# configure extra UI ENVs
|
||||
# Extra ENVs are writen in kubenertes format and added "as is" to the pod's env variables
|
||||
# https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/
|
||||
# https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables
|
||||
# UI specific env variables can be found here: https://github.com/zalando/postgres-operator/blob/master/ui/operator_ui/main.py
|
||||
extraEnvs:
|
||||
[]
|
||||
# Exemple of settings to make snapshot view working in the ui when using AWS
|
||||
# - name: SPILO_S3_BACKUP_PREFIX
|
||||
# value: spilo/
|
||||
# - name: AWS_ACCESS_KEY_ID
|
||||
# valueFrom:
|
||||
# secretKeyRef:
|
||||
# name: <postgres operator secret with AWS token>
|
||||
# key: AWS_ACCESS_KEY_ID
|
||||
# - name: AWS_SECRET_ACCESS_KEY
|
||||
# valueFrom:
|
||||
# secretKeyRef:
|
||||
# name: <postgres operator secret with AWS token>
|
||||
# key: AWS_SECRET_ACCESS_KEY
|
||||
# - name: AWS_DEFAULT_REGION
|
||||
# valueFrom:
|
||||
# secretKeyRef:
|
||||
# name: <postgres operator secret with AWS token>
|
||||
# key: AWS_DEFAULT_REGION
|
||||
# - name: SPILO_S3_BACKUP_BUCKET
|
||||
# value: <s3 bucket used by the operator>
|
||||
|
||||
# configure UI service
|
||||
service:
|
||||
type: "ClusterIP"
|
||||
|
|
@ -55,17 +89,36 @@ service:
|
|||
# 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
|
||||
# nodePort: 32521
|
||||
annotations:
|
||||
{}
|
||||
|
||||
# configure UI ingress. If needed: "enabled: true"
|
||||
ingress:
|
||||
enabled: false
|
||||
annotations: {}
|
||||
annotations:
|
||||
{}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
ingressClassName: ""
|
||||
hosts:
|
||||
- host: ui.example.org
|
||||
paths: [""]
|
||||
paths: ["/"]
|
||||
tls: []
|
||||
# - secretName: ui-tls
|
||||
# hosts:
|
||||
# - ui.exmaple.org
|
||||
|
||||
# priority class for operator-ui pod
|
||||
priorityClassName: ""
|
||||
|
||||
# Affinity for pod assignment
|
||||
# Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
|
||||
affinity: {}
|
||||
|
||||
# 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: []
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: v1
|
||||
apiVersion: v2
|
||||
name: postgres-operator
|
||||
version: 1.6.3
|
||||
appVersion: 1.6.3
|
||||
version: 1.15.1
|
||||
appVersion: 1.15.1
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
||||
keywords:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -4,8 +4,6 @@ metadata:
|
|||
name: postgresteams.acid.zalan.do
|
||||
labels:
|
||||
app.kubernetes.io/name: postgres-operator
|
||||
annotations:
|
||||
"helm.sh/hook": crd-install
|
||||
spec:
|
||||
group: acid.zalan.do
|
||||
names:
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
apiVersion: v1
|
||||
entries:
|
||||
postgres-operator:
|
||||
- apiVersion: v1
|
||||
appVersion: 1.6.3
|
||||
created: "2021-05-27T19:04:25.199523943+02:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
||||
digest: ea08f991bf23c9ad114bca98ebcbe3e2fa15beab163061399394905eaee89b35
|
||||
- apiVersion: v2
|
||||
appVersion: 1.15.1
|
||||
created: "2025-12-17T14:48:33.832345061+01:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||
in Kubernetes
|
||||
digest: 9f3edc3d796105c02c04eaae28a78e58fb08c1847a9de012245fd6ac2c0d2c00
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -20,13 +21,14 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-1.6.3.tgz
|
||||
version: 1.6.3
|
||||
- apiVersion: v1
|
||||
appVersion: 1.6.2
|
||||
created: "2021-05-27T19:04:25.198182197+02:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
||||
digest: d886f8a0879ca07d1e5246ee7bc55710e1c872f3977280fe495db6fc2057a7f4
|
||||
- postgres-operator-1.15.1.tgz
|
||||
version: 1.15.1
|
||||
- apiVersion: v2
|
||||
appVersion: 1.15.0
|
||||
created: "2025-12-17T14:48:33.826117296+01:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||
in Kubernetes
|
||||
digest: 002dd47647bf51fbba023bd1762d807be478cf37de7a44b80cd01ac1f20bd94a
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -41,13 +43,14 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-1.6.2.tgz
|
||||
version: 1.6.2
|
||||
- apiVersion: v1
|
||||
appVersion: 1.6.1
|
||||
created: "2021-05-27T19:04:25.19687586+02:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
||||
digest: 4ba5972cd486dcaa2d11c5613a6f97f6b7b831822e610fe9e10a57ea1db23556
|
||||
- postgres-operator-1.15.0.tgz
|
||||
version: 1.15.0
|
||||
- apiVersion: v2
|
||||
appVersion: 1.14.0
|
||||
created: "2025-12-17T14:48:33.819729144+01:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||
in Kubernetes
|
||||
digest: 36e1571f3f455b213f16cdda7b1158648e8e84deb804ba47ed6b9b6d19263ba8
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -62,13 +65,14 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-1.6.1.tgz
|
||||
version: 1.6.1
|
||||
- apiVersion: v1
|
||||
appVersion: 1.6.0
|
||||
created: "2021-05-27T19:04:25.195600766+02:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
||||
digest: f52149718ea364f46b4b9eec9a65f6253ad182bb78df541d14cd5277b9c8a8c3
|
||||
- postgres-operator-1.14.0.tgz
|
||||
version: 1.14.0
|
||||
- apiVersion: v2
|
||||
appVersion: 1.13.0
|
||||
created: "2025-12-17T14:48:33.81038602+01:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||
in Kubernetes
|
||||
digest: a839601689aea0a7e6bc0712a5244d435683cf3314c95794097ff08540e1dfef
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -83,13 +87,14 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-1.6.0.tgz
|
||||
version: 1.6.0
|
||||
- apiVersion: v1
|
||||
appVersion: 1.5.0
|
||||
created: "2021-05-27T19:04:25.193985032+02:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
||||
digest: 198351d5db52e65cdf383d6f3e1745d91ac1e2a01121f8476f8b1be728b09531
|
||||
- postgres-operator-1.13.0.tgz
|
||||
version: 1.13.0
|
||||
- apiVersion: v2
|
||||
appVersion: 1.12.2
|
||||
created: "2025-12-17T14:48:33.803256825+01:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||
in Kubernetes
|
||||
digest: 65858d14a40d7fd90c32bd9fc60021acc9555c161079f43a365c70171eaf21d8
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
|
|
@ -104,6 +109,50 @@ entries:
|
|||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-1.5.0.tgz
|
||||
version: 1.5.0
|
||||
generated: "2021-05-27T19:04:25.191897769+02:00"
|
||||
- postgres-operator-1.12.2.tgz
|
||||
version: 1.12.2
|
||||
- apiVersion: v2
|
||||
appVersion: 1.11.0
|
||||
created: "2025-12-17T14:48:33.797369053+01:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||
in Kubernetes
|
||||
digest: 3914b5e117bda0834f05c9207f007e2ac372864cf6e86dcc2e1362bbe46c14d9
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
- operator
|
||||
- cloud-native
|
||||
- patroni
|
||||
- spilo
|
||||
maintainers:
|
||||
- email: opensource@zalando.de
|
||||
name: Zalando
|
||||
name: postgres-operator
|
||||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-1.11.0.tgz
|
||||
version: 1.11.0
|
||||
- apiVersion: v2
|
||||
appVersion: 1.10.1
|
||||
created: "2025-12-17T14:48:33.791368349+01:00"
|
||||
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||
in Kubernetes
|
||||
digest: cc3baa41753da92466223d0b334df27e79c882296577b404a8e9071411fcf19c
|
||||
home: https://github.com/zalando/postgres-operator
|
||||
keywords:
|
||||
- postgres
|
||||
- operator
|
||||
- cloud-native
|
||||
- patroni
|
||||
- spilo
|
||||
maintainers:
|
||||
- email: opensource@zalando.de
|
||||
name: Zalando
|
||||
name: postgres-operator
|
||||
sources:
|
||||
- https://github.com/zalando/postgres-operator
|
||||
urls:
|
||||
- postgres-operator-1.10.1.tgz
|
||||
version: 1.10.1
|
||||
generated: "2025-12-17T14:48:33.785159183+01:00"
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -38,6 +38,13 @@ Create a pod service account name.
|
|||
{{ default (printf "%s-%v" (include "postgres-operator.fullname" .) "pod") .Values.podServiceAccount.name }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a pod priority class name.
|
||||
*/}}
|
||||
{{- define "postgres-pod.priorityClassName" -}}
|
||||
{{ default (printf "%s-%v" (include "postgres-operator.fullname" .) "pod") .Values.podPriorityClassName.name }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a controller ID.
|
||||
*/}}
|
||||
|
|
@ -57,18 +64,16 @@ Flatten nested config options when ConfigMap is used as ConfigTarget
|
|||
*/}}
|
||||
{{- define "flattenValuesForConfigMap" }}
|
||||
{{- range $key, $value := . }}
|
||||
{{- if or (kindIs "string" $value) (kindIs "int" $value) }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- if kindIs "slice" $value }}
|
||||
{{ $key }}: {{ join "," $value | quote }}
|
||||
{{- end }}
|
||||
{{- if kindIs "map" $value }}
|
||||
{{- else if kindIs "map" $value }}
|
||||
{{- $list := list }}
|
||||
{{- range $subKey, $subValue := $value }}
|
||||
{{- $list = append $list (printf "%s:%s" $subKey $subValue) }}
|
||||
{{ $key }}: {{ join "," $list | quote }}
|
||||
{{- end }}
|
||||
{{ $key }}: {{ join "," $list | quote }}
|
||||
{{- else }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ metadata:
|
|||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
rules:
|
||||
# Patroni needs to watch and manage endpoints
|
||||
# Patroni needs to watch and manage config maps or endpoints
|
||||
{{- if toString .Values.configGeneral.kubernetes_use_configmaps | eq "true" }}
|
||||
- apiGroups:
|
||||
- ""
|
||||
|
|
@ -24,12 +24,6 @@ rules:
|
|||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- endpoints
|
||||
verbs:
|
||||
- get
|
||||
{{- else }}
|
||||
- apiGroups:
|
||||
- ""
|
||||
|
|
|
|||
|
|
@ -34,16 +34,34 @@ rules:
|
|||
- get
|
||||
- list
|
||||
- watch
|
||||
# all verbs allowed for event streams
|
||||
{{- if .Values.enableStreams }}
|
||||
- apiGroups:
|
||||
- zalando.org
|
||||
resources:
|
||||
- fabriceventstreams
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- deletecollection
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
{{- end }}
|
||||
# to create or get/update CRDs when starting up
|
||||
- apiGroups:
|
||||
- apiextensions.k8s.io
|
||||
resources:
|
||||
- customresourcedefinitions
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
{{- if toString .Values.configGeneral.enable_crd_registration | eq "true" }}
|
||||
- create
|
||||
- patch
|
||||
- update
|
||||
{{- end }}
|
||||
# to send events to the CRs
|
||||
- apiGroups:
|
||||
- ""
|
||||
|
|
@ -71,12 +89,6 @@ rules:
|
|||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- endpoints
|
||||
verbs:
|
||||
- get
|
||||
{{- else }}
|
||||
# to read configuration from ConfigMaps
|
||||
- apiGroups:
|
||||
|
|
@ -108,6 +120,7 @@ rules:
|
|||
- create
|
||||
- delete
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
# to check nodes for node readiness label
|
||||
- apiGroups:
|
||||
|
|
@ -127,8 +140,8 @@ rules:
|
|||
- delete
|
||||
- get
|
||||
- list
|
||||
{{- if toString .Values.configKubernetes.storage_resize_mode | eq "pvc" }}
|
||||
- patch
|
||||
{{- if or (toString .Values.configKubernetes.storage_resize_mode | eq "pvc") (toString .Values.configKubernetes.storage_resize_mode | eq "mixed") }}
|
||||
- update
|
||||
{{- end }}
|
||||
# to read existing PVs. Creation should be done via dynamic provisioning
|
||||
|
|
@ -184,6 +197,7 @@ rules:
|
|||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
# to CRUD cron jobs for logical backups
|
||||
- apiGroups:
|
||||
- batch
|
||||
|
|
|
|||
|
|
@ -3,15 +3,16 @@ apiVersion: v1
|
|||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "postgres-operator.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
|
||||
helm.sh/chart: {{ template "postgres-operator.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
data:
|
||||
{{- if .Values.podPriorityClassName }}
|
||||
pod_priority_class_name: {{ .Values.podPriorityClassName }}
|
||||
{{- end }}
|
||||
{{- if or .Values.podPriorityClassName.create .Values.podPriorityClassName.name }}
|
||||
pod_priority_class_name: {{ include "postgres-pod.priorityClassName" . }}
|
||||
{{- end }}
|
||||
pod_service_account_name: {{ include "postgres-pod.serviceAccountName" . }}
|
||||
{{- include "flattenValuesForConfigMap" .Values.configGeneral | indent 2 }}
|
||||
{{- include "flattenValuesForConfigMap" .Values.configUsers | indent 2 }}
|
||||
|
|
@ -25,4 +26,5 @@ data:
|
|||
{{- include "flattenValuesForConfigMap" .Values.configLoggingRestApi | indent 2 }}
|
||||
{{- include "flattenValuesForConfigMap" .Values.configTeamsApi | indent 2 }}
|
||||
{{- include "flattenValuesForConfigMap" .Values.configConnectionPooler | indent 2 }}
|
||||
{{- include "flattenValuesForConfigMap" .Values.configPatroni | indent 2 }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
{{ if .Values.crd.create }}
|
||||
{{- range $path, $bytes := .Files.Glob "crds/*.yaml" }}
|
||||
{{ $.Files.Get $path }}
|
||||
---
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
@ -7,6 +7,7 @@ metadata:
|
|||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ template "postgres-operator.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
|
|
@ -36,6 +37,10 @@ spec:
|
|||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
{{- if .Values.extraArgs }}
|
||||
args:
|
||||
{{ toYaml .Values.extraArgs | indent 8 }}
|
||||
{{- end }}
|
||||
env:
|
||||
{{- if .Values.enableJsonLogging }}
|
||||
- name: ENABLE_JSON_LOGGING
|
||||
|
|
@ -51,11 +56,22 @@ spec:
|
|||
{{- if .Values.controllerID.create }}
|
||||
- name: CONTROLLER_ID
|
||||
value: {{ template "postgres-operator.controllerID" . }}
|
||||
{{- end }}
|
||||
{{- if .Values.extraEnvs }}
|
||||
{{ toYaml .Values.extraEnvs | indent 8 }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 10 }}
|
||||
securityContext:
|
||||
{{ toYaml .Values.securityContext | indent 10 }}
|
||||
{{- if .Values.readinessProbe }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: {{ .Values.configLoggingRestApi.api_port }}
|
||||
initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
|
||||
{{- end }}
|
||||
{{- if .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{ toYaml .Values.imagePullSecrets | indent 8 }}
|
||||
|
|
|
|||
|
|
@ -3,40 +3,43 @@ apiVersion: "acid.zalan.do/v1"
|
|||
kind: OperatorConfiguration
|
||||
metadata:
|
||||
name: {{ template "postgres-operator.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
|
||||
helm.sh/chart: {{ template "postgres-operator.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
configuration:
|
||||
{{ toYaml .Values.configGeneral | indent 2 }}
|
||||
{{ tpl (toYaml .Values.configGeneral) . | indent 2 }}
|
||||
users:
|
||||
{{ toYaml .Values.configUsers | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configUsers) . | indent 4 }}
|
||||
major_version_upgrade:
|
||||
{{ toYaml .Values.configMajorVersionUpgrade | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configMajorVersionUpgrade) . | indent 4 }}
|
||||
kubernetes:
|
||||
{{- if .Values.podPriorityClassName }}
|
||||
pod_priority_class_name: {{ .Values.podPriorityClassName }}
|
||||
{{- if .Values.podPriorityClassName.name }}
|
||||
pod_priority_class_name: {{ .Values.podPriorityClassName.name }}
|
||||
{{- end }}
|
||||
pod_service_account_name: {{ include "postgres-pod.serviceAccountName" . }}
|
||||
oauth_token_secret_name: {{ template "postgres-operator.fullname" . }}
|
||||
{{ toYaml .Values.configKubernetes | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configKubernetes) . | indent 4 }}
|
||||
postgres_pod_resources:
|
||||
{{ toYaml .Values.configPostgresPodResources | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configPostgresPodResources) . | indent 4 }}
|
||||
timeouts:
|
||||
{{ toYaml .Values.configTimeouts | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configTimeouts) . | indent 4 }}
|
||||
load_balancer:
|
||||
{{ toYaml .Values.configLoadBalancer | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configLoadBalancer) . | indent 4 }}
|
||||
aws_or_gcp:
|
||||
{{ toYaml .Values.configAwsOrGcp | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configAwsOrGcp) . | indent 4 }}
|
||||
logical_backup:
|
||||
{{ toYaml .Values.configLogicalBackup | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configLogicalBackup) . | indent 4 }}
|
||||
debug:
|
||||
{{ toYaml .Values.configDebug | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configDebug) . | indent 4 }}
|
||||
teams_api:
|
||||
{{ toYaml .Values.configTeamsApi | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configTeamsApi) . | indent 4 }}
|
||||
logging_rest_api:
|
||||
{{ toYaml .Values.configLoggingRestApi | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configLoggingRestApi) . | indent 4 }}
|
||||
connection_pooler:
|
||||
{{ toYaml .Values.configConnectionPooler | indent 4 }}
|
||||
{{ tpl (toYaml .Values.configConnectionPooler) . | indent 4 }}
|
||||
patroni:
|
||||
{{ tpl (toYaml .Values.configPatroni) . | indent 4 }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{{- if .Values.podPriorityClassName }}
|
||||
{{- if .Values.podPriorityClassName.create }}
|
||||
apiVersion: scheduling.k8s.io/v1
|
||||
description: 'Use only for databases controlled by Postgres operator'
|
||||
kind: PriorityClass
|
||||
|
|
@ -8,8 +8,9 @@ metadata:
|
|||
helm.sh/chart: {{ template "postgres-operator.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ .Values.podPriorityClassName }}
|
||||
name: {{ include "postgres-pod.priorityClassName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
preemptionPolicy: PreemptLowerPriority
|
||||
globalDefault: false
|
||||
value: 1000000
|
||||
value: {{ .Values.podPriorityClassName.priority }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ metadata:
|
|||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ template "postgres-operator.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ apiVersion: v1
|
|||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "postgres-operator.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
|
||||
helm.sh/chart: {{ template "postgres-operator.chart" . }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
{{ if .Values.rbac.createAggregateClusterRoles }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
|
||||
helm.sh/chart: {{ template "postgres-operator.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ template "postgres-operator.fullname" . }}:users:admin
|
||||
rules:
|
||||
- apiGroups:
|
||||
- acid.zalan.do
|
||||
resources:
|
||||
- postgresqls
|
||||
- postgresqls/status
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- deletecollection
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
rbac.authorization.k8s.io/aggregate-to-edit: "true"
|
||||
app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
|
||||
helm.sh/chart: {{ template "postgres-operator.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ template "postgres-operator.fullname" . }}:users:edit
|
||||
rules:
|
||||
- apiGroups:
|
||||
- acid.zalan.do
|
||||
resources:
|
||||
- postgresqls
|
||||
verbs:
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
rbac.authorization.k8s.io/aggregate-to-view: "true"
|
||||
app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
|
||||
helm.sh/chart: {{ template "postgres-operator.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
name: {{ template "postgres-operator.fullname" . }}:users:view
|
||||
rules:
|
||||
- apiGroups:
|
||||
- acid.zalan.do
|
||||
resources:
|
||||
- postgresqls
|
||||
- postgresqls/status
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
{{ end }}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
image:
|
||||
registry: registry.opensource.zalan.do
|
||||
repository: acid/postgres-operator
|
||||
tag: v1.6.3
|
||||
registry: ghcr.io
|
||||
repository: zalando/postgres-operator
|
||||
tag: v1.15.1
|
||||
pullPolicy: "IfNotPresent"
|
||||
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
# imagePullSecrets:
|
||||
# - name: myRegistryKeySecretName
|
||||
# Optionally specify an array of imagePullSecrets.
|
||||
# Secrets must be manually created in the namespace.
|
||||
# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
||||
# imagePullSecrets:
|
||||
# - name: myRegistryKeySecretName
|
||||
|
||||
podAnnotations: {}
|
||||
podLabels: {}
|
||||
|
|
@ -18,24 +18,44 @@ configTarget: "OperatorConfigurationCRD"
|
|||
# JSON logging format
|
||||
enableJsonLogging: false
|
||||
|
||||
# Command-line options for the operator
|
||||
extraArgs: []
|
||||
|
||||
# general configuration parameters
|
||||
configGeneral:
|
||||
# choose if deployment creates/updates CRDs with OpenAPIV3Validation
|
||||
enable_crd_validation: true
|
||||
# the deployment should create/update the CRDs
|
||||
enable_crd_registration: true
|
||||
# specify categories under which crds should be listed
|
||||
crd_categories:
|
||||
- "all"
|
||||
# update only the statefulsets without immediately doing the rolling update
|
||||
enable_lazy_spilo_upgrade: false
|
||||
# toogle to use maintenance windows feature
|
||||
enable_maintenance_windows: true
|
||||
# set the PGVERSION env var instead of providing the version via postgresql.bin_dir in SPILO_CONFIGURATION
|
||||
enable_pgversion_env_var: true
|
||||
# start any new database pod without limitations on shm memory
|
||||
enable_shm_volume: true
|
||||
# enables backwards compatible path between Spilo 12 and Spilo 13 images
|
||||
enable_spilo_wal_path_compat: false
|
||||
# operator will sync only clusters where name starts with teamId prefix
|
||||
enable_team_id_clustername_prefix: false
|
||||
# etcd connection string for Patroni. Empty uses K8s-native DCS.
|
||||
etcd_host: ""
|
||||
# Spilo docker image
|
||||
docker_image: ghcr.io/zalando/spilo-18:4.1-p1
|
||||
|
||||
# key name for annotation to ignore globally configured instance limits
|
||||
# ignore_instance_limits_annotation_key: ""
|
||||
|
||||
# key name for annotation to ignore globally configured resources thresholds
|
||||
# ignore_resources_limits_annotation_key: ""
|
||||
|
||||
# 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-p7
|
||||
|
||||
# maintenance windows applied to all Postgres clusters unless overridden in the manifest
|
||||
# maintenance_windows:
|
||||
# - "Sun:01:00-06:00"
|
||||
|
||||
# min number of instances in Postgres cluster. -1 = no limit
|
||||
min_instances: -1
|
||||
# max number of instances in Postgres cluster. -1 = no limit
|
||||
|
|
@ -56,6 +76,16 @@ configGeneral:
|
|||
|
||||
# parameters describing Postgres users
|
||||
configUsers:
|
||||
# roles to be granted to database owners
|
||||
# additional_owner_roles:
|
||||
# - cron_admin
|
||||
|
||||
# enable password rotation for app users that are not database owners
|
||||
enable_password_rotation: false
|
||||
# rotation interval for updating credentials in K8s secrets of app users
|
||||
password_rotation_interval: 90
|
||||
# retention interval to keep rotation users
|
||||
password_rotation_user_retention: 180
|
||||
# postgres username used for replication between instances
|
||||
replication_username: standby
|
||||
# postgres superuser name to be created by initdb
|
||||
|
|
@ -63,11 +93,15 @@ configUsers:
|
|||
|
||||
configMajorVersionUpgrade:
|
||||
# "off": no upgrade, "manual": manifest triggers action, "full": minimal version violation triggers too
|
||||
major_version_upgrade_mode: "off"
|
||||
major_version_upgrade_mode: "manual"
|
||||
# upgrades will only be carried out for clusters of listed teams when mode is "off"
|
||||
# major_version_upgrade_team_allow_list:
|
||||
# - acid
|
||||
|
||||
# minimal Postgres major version that will not automatically be upgraded
|
||||
minimal_major_version: "9.5"
|
||||
minimal_major_version: "14"
|
||||
# target Postgres major version when upgrading clusters automatically
|
||||
target_major_version: "13"
|
||||
target_major_version: "18"
|
||||
|
||||
configKubernetes:
|
||||
# list of additional capabilities for postgres container
|
||||
|
|
@ -97,14 +131,33 @@ configKubernetes:
|
|||
# - deployment-time
|
||||
# - downscaler/*
|
||||
|
||||
# allow user secrets in other namespaces than the Postgres cluster
|
||||
enable_cross_namespace_secret: false
|
||||
# use finalizers to ensure all managed resources are deleted prior to the postgresql CR
|
||||
# this avoids stale resources in case the operator misses a delete event or is not running
|
||||
# during deletion
|
||||
enable_finalizers: false
|
||||
# enables initContainers to run actions before Spilo is started
|
||||
enable_init_containers: true
|
||||
# toggles if child resources should have an owner reference to the postgresql CR
|
||||
enable_owner_references: false
|
||||
# toggles if operator should delete PVCs on cluster deletion
|
||||
enable_persistent_volume_claim_deletion: true
|
||||
# toggles pod anti affinity on the Postgres pods
|
||||
enable_pod_antiaffinity: false
|
||||
# toggles PDB to set to MinAvailabe 0 or 1
|
||||
enable_pod_disruption_budget: true
|
||||
# toogles readiness probe for database pods
|
||||
enable_readiness_probe: false
|
||||
# toggles if operator should delete secrets on cluster deletion
|
||||
enable_secrets_deletion: true
|
||||
# enables sidecar containers to run alongside Spilo in the same pod
|
||||
enable_sidecars: true
|
||||
|
||||
# annotations to be ignored when comparing statefulsets, services etc.
|
||||
# ignored_annotations:
|
||||
# - k8s.v1.cni.cncf.io/network-status
|
||||
|
||||
# namespaced name of the secret containing infrastructure roles names and passwords
|
||||
# infrastructure_roles_secret_name: postgresql-infrastructure-roles
|
||||
|
||||
|
|
@ -124,11 +177,22 @@ configKubernetes:
|
|||
# node_readiness_label:
|
||||
# status: ready
|
||||
|
||||
# defines how nodeAffinity from manifest should be merged with node_readiness_label
|
||||
# node_readiness_label_merge: "OR"
|
||||
|
||||
# namespaced name of the secret containing the OAuth2 token to pass to the teams API
|
||||
# oauth_token_secret_name: postgresql-operator
|
||||
|
||||
# defines the template for PDB (Pod Disruption Budget) names
|
||||
# toggle if `spilo-role=master` selector should be added to the PDB (Pod Disruption Budget)
|
||||
pdb_master_label_selector: true
|
||||
# defines the template for PDB names
|
||||
pdb_name_format: "postgres-{cluster}-pdb"
|
||||
# specify the PVC retention policy when scaling down and/or deleting
|
||||
persistent_volume_claim_retention_policy:
|
||||
when_deleted: "retain"
|
||||
when_scaled: "retain"
|
||||
# switches pod anti affinity type to `preferredDuringSchedulingIgnoredDuringExecution`
|
||||
pod_antiaffinity_preferred_during_scheduling: false
|
||||
# override topology key for pod anti affinity
|
||||
pod_antiaffinity_topology_key: "kubernetes.io/hostname"
|
||||
# namespaced name of the ConfigMap with environment variables to populate on every pod
|
||||
|
|
@ -148,11 +212,17 @@ configKubernetes:
|
|||
|
||||
# Postgres pods are terminated forcefully after this timeout
|
||||
pod_terminate_grace_period: 5m
|
||||
# template for database user secrets generated by the operator
|
||||
# template for database user secrets generated by the operator,
|
||||
# here username contains the namespace in the format namespace.username
|
||||
# if the user is in different namespace than cluster and cross namespace secrets
|
||||
# are enabled via `enable_cross_namespace_secret` flag in the configuration.
|
||||
secret_name_template: "{username}.{cluster}.credentials.{tprkind}.{tprgroup}"
|
||||
# sharing unix socket of PostgreSQL (`pg_socket`) with the sidecars
|
||||
share_pgsocket_with_sidecars: false
|
||||
# set user and group for the spilo container (required to run Spilo as non-root process)
|
||||
# spilo_runasuser: 101
|
||||
# spilo_runasgroup: 103
|
||||
|
||||
# group ID with write-access to volumes (required to run Spilo as non-root process)
|
||||
# spilo_fsgroup: 103
|
||||
|
||||
|
|
@ -161,8 +231,27 @@ configKubernetes:
|
|||
# whether the Spilo container should run with additional permissions other than parent.
|
||||
# required by cron which needs setuid
|
||||
spilo_allow_privilege_escalation: true
|
||||
# storage resize strategy, available options are: ebs, pvc, off
|
||||
|
||||
# liveness probe for the spilo pod
|
||||
# liveness_probe:
|
||||
# httpGet:
|
||||
# scheme: HTTP
|
||||
# path: /liveness
|
||||
# port: 8008
|
||||
# initialDelaySeconds: 10
|
||||
# periodSeconds: 10
|
||||
# timeoutSeconds: 5
|
||||
# successThreshold: 1
|
||||
# failureThreshold: 3
|
||||
|
||||
# storage resize strategy, available options are: ebs, pvc, off or mixed
|
||||
storage_resize_mode: pvc
|
||||
# pod toleration assigned to instances of every Postgres cluster
|
||||
# toleration:
|
||||
# key: db-only
|
||||
# operator: Exists
|
||||
# effect: NoSchedule
|
||||
|
||||
# operator watches for postgres objects in the given namespace
|
||||
watched_namespace: "*" # listen to all namespaces
|
||||
|
||||
|
|
@ -176,6 +265,12 @@ configPostgresPodResources:
|
|||
default_memory_limit: 500Mi
|
||||
# memory request value for the postgres containers
|
||||
default_memory_request: 100Mi
|
||||
# optional upper boundary for CPU request
|
||||
# max_cpu_request: "1"
|
||||
|
||||
# optional upper boundary for memory request
|
||||
# max_memory_request: 4Gi
|
||||
|
||||
# hard CPU minimum required to properly run a Postgres cluster
|
||||
min_cpu_limit: 250m
|
||||
# hard memory minimum required to properly run a Postgres cluster
|
||||
|
|
@ -183,6 +278,10 @@ configPostgresPodResources:
|
|||
|
||||
# timeouts related to some operator actions
|
||||
configTimeouts:
|
||||
# interval between consecutive attempts of operator calling the Patroni API
|
||||
patroni_api_check_interval: 1s
|
||||
# timeout when waiting for successful response from Patroni API
|
||||
patroni_api_check_timeout: 5s
|
||||
# timeout when waiting for the Postgres pods to be deleted
|
||||
pod_deletion_wait_timeout: 10m
|
||||
# timeout when waiting for pod role and cluster labels
|
||||
|
|
@ -207,14 +306,22 @@ configLoadBalancer:
|
|||
|
||||
# toggles service type load balancer pointing to the master pod of the cluster
|
||||
enable_master_load_balancer: false
|
||||
# toggles service type load balancer pointing to the master pooler pod of the cluster
|
||||
enable_master_pooler_load_balancer: false
|
||||
# toggles service type load balancer pointing to the replica pod of the cluster
|
||||
enable_replica_load_balancer: false
|
||||
# toggles service type load balancer pointing to the replica pooler pod of the cluster
|
||||
enable_replica_pooler_load_balancer: false
|
||||
# define external traffic policy for the load balancer
|
||||
external_traffic_policy: "Cluster"
|
||||
# defines the DNS name string template for the master load balancer cluster
|
||||
master_dns_name_format: "{cluster}.{team}.{hostedzone}"
|
||||
master_dns_name_format: "{cluster}.{namespace}.{hostedzone}"
|
||||
# deprecated DNS template for master load balancer using team name
|
||||
master_legacy_dns_name_format: "{cluster}.{team}.{hostedzone}"
|
||||
# defines the DNS name string template for the replica load balancer cluster
|
||||
replica_dns_name_format: "{cluster}-repl.{team}.{hostedzone}"
|
||||
replica_dns_name_format: "{cluster}-repl.{namespace}.{hostedzone}"
|
||||
# deprecated DNS template for replica load balancer using team name
|
||||
replica_legacy_dns_name_format: "{cluster}-repl.{team}.{hostedzone}"
|
||||
|
||||
# options to aid debugging of the operator itself
|
||||
configDebug:
|
||||
|
|
@ -240,7 +347,7 @@ configAwsOrGcp:
|
|||
# Path to mount the above Secret in the filesystem of the container(s)
|
||||
# additional_secret_mount_path: "/some/dir"
|
||||
|
||||
# AWS region used to store ESB volumes
|
||||
# AWS region used to store EBS volumes
|
||||
aws_region: eu-central-1
|
||||
|
||||
# enable automatic migration on AWS from gp2 to gp3 volumes
|
||||
|
|
@ -263,21 +370,37 @@ configAwsOrGcp:
|
|||
# GCS bucket to use for shipping WAL segments with WAL-E
|
||||
# wal_gs_bucket: ""
|
||||
|
||||
# Azure Storage Account to use for shipping WAL segments with WAL-G
|
||||
# wal_az_storage_account: ""
|
||||
|
||||
# configure K8s cron job managed by the operator
|
||||
configLogicalBackup:
|
||||
# Azure Storage Account specs to store backup results
|
||||
# logical_backup_azure_storage_account_name: ""
|
||||
# logical_backup_azure_storage_container: ""
|
||||
# logical_backup_azure_storage_account_key: ""
|
||||
|
||||
# resources for logical backup pod, if empty configPostgresPodResources will be used
|
||||
# logical_backup_cpu_limit: ""
|
||||
# logical_backup_cpu_request: ""
|
||||
# logical_backup_memory_limit: ""
|
||||
# logical_backup_memory_request: ""
|
||||
|
||||
# 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.3"
|
||||
logical_backup_docker_image: "ghcr.io/zalando/postgres-operator/logical-backup:v1.15.1"
|
||||
# path of google cloud service account json file
|
||||
# logical_backup_google_application_credentials: ""
|
||||
|
||||
# prefix for the backup job name
|
||||
logical_backup_job_prefix: "logical-backup-"
|
||||
# storage provider - either "s3" or "gcs"
|
||||
# storage provider - either "s3", "gcs" or "az"
|
||||
logical_backup_provider: "s3"
|
||||
# S3 Access Key ID
|
||||
logical_backup_s3_access_key_id: ""
|
||||
# S3 bucket to store backup results
|
||||
logical_backup_s3_bucket: "my-bucket-url"
|
||||
# S3 bucket prefix to use
|
||||
logical_backup_s3_bucket_prefix: "spilo"
|
||||
# S3 region of bucket
|
||||
logical_backup_s3_region: ""
|
||||
# S3 endpoint url when not using AWS
|
||||
|
|
@ -286,8 +409,18 @@ configLogicalBackup:
|
|||
logical_backup_s3_secret_access_key: ""
|
||||
# S3 server side encryption
|
||||
logical_backup_s3_sse: "AES256"
|
||||
# S3 retention time for stored backups for example "2 week" or "7 days"
|
||||
logical_backup_s3_retention_time: ""
|
||||
# backup schedule in the cron format
|
||||
logical_backup_schedule: "30 00 * * *"
|
||||
# secret to be used as reference for env variables in cronjob
|
||||
logical_backup_cronjob_environment_secret: ""
|
||||
# number of successful backup jobs to keep in cronjob history
|
||||
logical_backup_successful_jobs_history_limit: 3
|
||||
# number of failed backup jobs to keep in cronjob history
|
||||
logical_backup_failed_jobs_history_limit: 3
|
||||
# TTL in seconds after which finished backup jobs are automatically deleted
|
||||
logical_backup_ttl_seconds_after_finished: 86400
|
||||
|
||||
# automate creation of human users with teams API service
|
||||
configTeamsApi:
|
||||
|
|
@ -314,6 +447,7 @@ configTeamsApi:
|
|||
# List of roles that cannot be overwritten by an application, team or infrastructure role
|
||||
protected_role_names:
|
||||
- admin
|
||||
- cron_admin
|
||||
# Suffix to add if members are removed from TeamsAPI or PostgresTeam CRD
|
||||
role_deletion_suffix: "_deleted"
|
||||
# role name to grant to team members created from the Teams API
|
||||
|
|
@ -331,7 +465,7 @@ configConnectionPooler:
|
|||
# db user for pooler to use
|
||||
connection_pooler_user: "pooler"
|
||||
# docker image
|
||||
connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-16"
|
||||
connection_pooler_image: "ghcr.io/zalando/postgres-operator/pgbouncer:latest"
|
||||
# max db connections the pooler should hold
|
||||
connection_pooler_max_db_connections: 60
|
||||
# default pooling mode
|
||||
|
|
@ -344,14 +478,18 @@ configConnectionPooler:
|
|||
connection_pooler_default_cpu_limit: "1"
|
||||
connection_pooler_default_memory_limit: 100Mi
|
||||
|
||||
configPatroni:
|
||||
# enable Patroni DCS failsafe_mode feature
|
||||
enable_patroni_failsafe_mode: false
|
||||
|
||||
# Zalando's internal CDC stream feature
|
||||
enableStreams: false
|
||||
|
||||
rbac:
|
||||
# Specifies whether RBAC resources should be created
|
||||
create: true
|
||||
|
||||
crd:
|
||||
# Specifies whether custom resource definitions should be created
|
||||
# When using helm3, this is ignored; instead use "--skip-crds" to skip.
|
||||
create: true
|
||||
# Specifies whether ClusterRoles that are aggregated into the K8s default roles should be created. (https://kubernetes.io/docs/reference/access-authn-authz/rbac/#default-roles-and-role-bindings)
|
||||
createAggregateClusterRoles: false
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a ServiceAccount should be created
|
||||
|
|
@ -369,7 +507,14 @@ podServiceAccount:
|
|||
priorityClassName: ""
|
||||
|
||||
# priority class for database pods
|
||||
podPriorityClassName: ""
|
||||
podPriorityClassName:
|
||||
# If create is false with no name set, no podPriorityClassName is specified.
|
||||
# Hence, the pod priorityClass is the one with globalDefault set.
|
||||
# If there is no PriorityClass with globalDefault set, the priority of Pods with no priorityClassName is zero.
|
||||
create: true
|
||||
# If not set a name is generated using the fullname template and "-pod" suffix
|
||||
name: ""
|
||||
priority: 1000000
|
||||
|
||||
resources:
|
||||
limits:
|
||||
|
|
@ -385,6 +530,29 @@ securityContext:
|
|||
readOnlyRootFilesystem: true
|
||||
allowPrivilegeEscalation: false
|
||||
|
||||
# Allow to setup operator Deployment readiness probe
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
||||
# configure extra environment variables
|
||||
# Extra environment variables are writen in kubernetes format and added "as is" to the pod's env variables
|
||||
# https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/
|
||||
# https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables
|
||||
extraEnvs:
|
||||
[]
|
||||
# Exemple of settings maximum amount of memory / cpu that can be used by go process (to match resources.limits)
|
||||
# - name: MY_VAR
|
||||
# value: my-value
|
||||
# - name: GOMAXPROCS
|
||||
# valueFrom:
|
||||
# resourceFieldRef:
|
||||
# resource: limits.cpu
|
||||
# - name: GOMEMLIMIT
|
||||
# valueFrom:
|
||||
# resourceFieldRef:
|
||||
# resource: limits.memory
|
||||
|
||||
# Affinity for pod assignment
|
||||
# Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
|
||||
affinity: {}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/zalando/postgres-operator/pkg/controller"
|
||||
"github.com/zalando/postgres-operator/pkg/spec"
|
||||
"github.com/zalando/postgres-operator/pkg/util/k8sutil"
|
||||
|
|
@ -34,6 +35,8 @@ func init() {
|
|||
flag.BoolVar(&outOfCluster, "outofcluster", false, "Whether the operator runs in- our outside of the Kubernetes cluster.")
|
||||
flag.BoolVar(&config.NoDatabaseAccess, "nodatabaseaccess", false, "Disable all access to the database from the operator side.")
|
||||
flag.BoolVar(&config.NoTeamsAPI, "noteamsapi", false, "Disable all access to the teams API")
|
||||
flag.IntVar(&config.KubeQPS, "kubeqps", 10, "Kubernetes api requests per second.")
|
||||
flag.IntVar(&config.KubeBurst, "kubeburst", 20, "Kubernetes api requests burst limit.")
|
||||
flag.Parse()
|
||||
|
||||
config.EnableJsonLogging = os.Getenv("ENABLE_JSON_LOGGING") == "true"
|
||||
|
|
@ -82,6 +85,9 @@ func main() {
|
|||
log.Fatalf("couldn't get REST config: %v", err)
|
||||
}
|
||||
|
||||
config.RestConfig.QPS = float32(config.KubeQPS)
|
||||
config.RestConfig.Burst = config.KubeBurst
|
||||
|
||||
c := controller.NewController(&config, "")
|
||||
|
||||
c.Run(stop, wg)
|
||||
|
|
|
|||
214
delivery.yaml
214
delivery.yaml
|
|
@ -1,94 +1,136 @@
|
|||
version: "2017-09-20"
|
||||
allow_concurrent_steps: true
|
||||
|
||||
build_env: &BUILD_ENV
|
||||
PYTHON_BASE_IMAGE: container-registry.zalando.net/library/python-3.11-slim
|
||||
ALPINE_BASE_IMAGE: container-registry.zalando.net/library/alpine-3
|
||||
UBUNTU_BASE_IMAGE: container-registry.zalando.net/library/ubuntu-22.04
|
||||
MULTI_ARCH_REGISTRY: container-registry-test.zalando.net/acid
|
||||
|
||||
pipeline:
|
||||
- id: build-postgres-operator
|
||||
type: script
|
||||
vm: large
|
||||
cache:
|
||||
paths:
|
||||
- /go/pkg/mod
|
||||
commands:
|
||||
- desc: 'Update'
|
||||
cmd: |
|
||||
apt-get update
|
||||
- desc: 'Install required build software'
|
||||
cmd: |
|
||||
apt-get install -y make git apt-transport-https ca-certificates curl build-essential python3 python3-pip
|
||||
- desc: 'Install go'
|
||||
cmd: |
|
||||
cd /tmp
|
||||
wget -q https://storage.googleapis.com/golang/go1.15.6.linux-amd64.tar.gz -O go.tar.gz
|
||||
tar -xf go.tar.gz
|
||||
mv go /usr/local
|
||||
ln -s /usr/local/go/bin/go /usr/bin/go
|
||||
go version
|
||||
- desc: 'Build docker image'
|
||||
cmd: |
|
||||
export PATH=$PATH:$HOME/go/bin
|
||||
IS_PR_BUILD=${CDP_PULL_REQUEST_NUMBER+"true"}
|
||||
if [[ ${CDP_TARGET_BRANCH} == "master" && ${IS_PR_BUILD} != "true" ]]
|
||||
then
|
||||
IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator
|
||||
else
|
||||
IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator-test
|
||||
fi
|
||||
export IMAGE
|
||||
make deps mocks docker
|
||||
- desc: 'Run unit tests'
|
||||
cmd: |
|
||||
export PATH=$PATH:$HOME/go/bin
|
||||
go test ./...
|
||||
- desc: 'Run e2e tests'
|
||||
cmd: |
|
||||
make e2e
|
||||
- desc: 'Push docker image'
|
||||
cmd: |
|
||||
export PATH=$PATH:$HOME/go/bin
|
||||
IS_PR_BUILD=${CDP_PULL_REQUEST_NUMBER+"true"}
|
||||
if [[ ${CDP_TARGET_BRANCH} == "master" && ${IS_PR_BUILD} != "true" ]]
|
||||
then
|
||||
IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator
|
||||
else
|
||||
IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator-test
|
||||
fi
|
||||
export IMAGE
|
||||
make push
|
||||
- id: build-postgres-operator
|
||||
env:
|
||||
<<: *BUILD_ENV
|
||||
type: script
|
||||
vm_config:
|
||||
type: linux
|
||||
size: large
|
||||
image: cdp-runtime/go
|
||||
cache:
|
||||
paths:
|
||||
- /go/pkg/mod # pkg cache for Go modules
|
||||
- ~/.cache/go-build # Go build cache
|
||||
commands:
|
||||
- desc: Run unit tests
|
||||
cmd: |
|
||||
make mocks test
|
||||
if ! git diff --quiet; then
|
||||
echo "Build resulted in files being changed, likely they were not checked in"
|
||||
exit 1
|
||||
fi
|
||||
- desc: Build Docker image
|
||||
cmd: |
|
||||
if [ -z ${CDP_SOURCE_BRANCH} ]; then
|
||||
IMAGE=${MULTI_ARCH_REGISTRY}/postgres-operator
|
||||
else
|
||||
IMAGE=${MULTI_ARCH_REGISTRY}/postgres-operator-test
|
||||
fi
|
||||
|
||||
- id: build-operator-ui
|
||||
type: script
|
||||
docker buildx create --config /etc/cdp-buildkitd.toml --driver-opt network=host --bootstrap --use
|
||||
docker buildx build --platform "linux/amd64,linux/arm64" \
|
||||
--build-arg BASE_IMAGE="${ALPINE_BASE_IMAGE}" \
|
||||
-t "${IMAGE}:${CDP_BUILD_VERSION}" \
|
||||
-f docker/Dockerfile \
|
||||
--push .
|
||||
|
||||
commands:
|
||||
- desc: 'Prepare environment'
|
||||
cmd: |
|
||||
apt-get update
|
||||
apt-get install -y build-essential
|
||||
- id: build-pooler
|
||||
env:
|
||||
<<: *BUILD_ENV
|
||||
type: script
|
||||
vm_config:
|
||||
type: linux
|
||||
|
||||
- desc: 'Compile JavaScript app'
|
||||
cmd: |
|
||||
cd ui
|
||||
make appjs
|
||||
commands:
|
||||
- desc: Build image
|
||||
cmd: |
|
||||
cd pooler
|
||||
if [ -z ${CDP_SOURCE_BRANCH} ]; then
|
||||
IMAGE=${MULTI_ARCH_REGISTRY}/pgbouncer
|
||||
else
|
||||
IMAGE=${MULTI_ARCH_REGISTRY}/pgbouncer-test
|
||||
fi
|
||||
|
||||
- desc: 'Build and push Docker image'
|
||||
cmd: |
|
||||
cd ui
|
||||
IS_PR_BUILD=${CDP_PULL_REQUEST_NUMBER+"true"}
|
||||
if [[ ${CDP_TARGET_BRANCH} == "master" && ${IS_PR_BUILD} != "true" ]]
|
||||
then
|
||||
IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator-ui
|
||||
else
|
||||
IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator-ui-test
|
||||
fi
|
||||
export IMAGE
|
||||
make docker
|
||||
make push
|
||||
docker buildx create --config /etc/cdp-buildkitd.toml --driver-opt network=host --bootstrap --use
|
||||
docker buildx build --platform "linux/amd64,linux/arm64" \
|
||||
--build-arg BASE_IMAGE="${ALPINE_BASE_IMAGE}" \
|
||||
-t "${IMAGE}:${CDP_BUILD_VERSION}" \
|
||||
--push .
|
||||
|
||||
- id: build-logical-backup
|
||||
type: script
|
||||
if [ -z ${CDP_SOURCE_BRANCH} ]; then
|
||||
cdp-promote-image ${IMAGE}:${CDP_BUILD_VERSION}
|
||||
fi
|
||||
|
||||
commands:
|
||||
- desc: Build image
|
||||
cmd: |
|
||||
cd docker/logical-backup
|
||||
export TAG=$(git describe --tags --always --dirty)
|
||||
IMAGE="registry-write.opensource.zalan.do/acid/logical-backup"
|
||||
docker build --rm -t "$IMAGE:$TAG$CDP_TAG" .
|
||||
docker push "$IMAGE:$TAG$CDP_TAG"
|
||||
- id: build-operator-ui
|
||||
env:
|
||||
<<: *BUILD_ENV
|
||||
type: script
|
||||
vm_config:
|
||||
type: linux
|
||||
|
||||
commands:
|
||||
- desc: 'Prepare environment'
|
||||
cmd: |
|
||||
apt-get update
|
||||
apt-get install -y build-essential
|
||||
|
||||
- desc: 'Compile JavaScript app'
|
||||
cmd: |
|
||||
cd ui
|
||||
make appjs
|
||||
|
||||
- desc: 'Build and push Docker image'
|
||||
cmd: |
|
||||
cd ui
|
||||
if [ -z ${CDP_SOURCE_BRANCH} ]; then
|
||||
IMAGE=${MULTI_ARCH_REGISTRY}/postgres-operator-ui
|
||||
else
|
||||
IMAGE=${MULTI_ARCH_REGISTRY}/postgres-operator-ui-test
|
||||
fi
|
||||
|
||||
make appjs
|
||||
docker buildx create --config /etc/cdp-buildkitd.toml --driver-opt network=host --bootstrap --use
|
||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
||||
--build-arg BASE_IMAGE="${PYTHON_BASE_IMAGE}" \
|
||||
-t ${IMAGE}:${CDP_BUILD_VERSION} \
|
||||
--push .
|
||||
|
||||
if [ -z ${CDP_SOURCE_BRANCH} ]; then
|
||||
cdp-promote-image ${IMAGE}:${CDP_BUILD_VERSION}
|
||||
fi
|
||||
|
||||
- id: build-logical-backup
|
||||
env:
|
||||
<<: *BUILD_ENV
|
||||
type: script
|
||||
vm_config:
|
||||
type: linux
|
||||
|
||||
commands:
|
||||
- desc: Build image
|
||||
cmd: |
|
||||
cd logical-backup
|
||||
if [ -z ${CDP_SOURCE_BRANCH} ]; then
|
||||
IMAGE=${MULTI_ARCH_REGISTRY}/logical-backup
|
||||
else
|
||||
IMAGE=${MULTI_ARCH_REGISTRY}/logical-backup-test
|
||||
fi
|
||||
|
||||
docker buildx create --config /etc/cdp-buildkitd.toml --driver-opt network=host --bootstrap --use
|
||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
||||
--build-arg BASE_IMAGE="${UBUNTU_BASE_IMAGE}" \
|
||||
-t ${IMAGE}:${CDP_BUILD_VERSION} \
|
||||
--push .
|
||||
|
||||
if [ -z ${CDP_SOURCE_BRANCH} ]; then
|
||||
cdp-promote-image ${IMAGE}:${CDP_BUILD_VERSION}
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
FROM registry.opensource.zalan.do/library/alpine-3.12:latest
|
||||
FROM golang:1.26-alpine
|
||||
LABEL maintainer="Team ACID @ Zalando <team-acid@zalando.de>"
|
||||
|
||||
# We need root certificates to deal with teams api over https
|
||||
RUN apk --no-cache add ca-certificates go git musl-dev
|
||||
RUN apk -U add --no-cache ca-certificates delve
|
||||
|
||||
COPY build/* /
|
||||
|
||||
RUN addgroup -g 1000 pgo
|
||||
RUN adduser -D -u 1000 -G pgo -g 'Postgres Operator' pgo
|
||||
|
||||
RUN go get github.com/derekparker/delve/cmd/dlv
|
||||
RUN cp /root/go/bin/dlv /dlv
|
||||
RUN chown -R pgo:pgo /dlv
|
||||
|
||||
USER pgo:pgo
|
||||
RUN ls -l /
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,27 @@
|
|||
FROM registry.opensource.zalan.do/library/alpine-3.12:latest
|
||||
ARG BASE_IMAGE=alpine:latest
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder
|
||||
ARG VERSION=latest
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
COPY . /go/src/github.com/zalando/postgres-operator
|
||||
WORKDIR /go/src/github.com/zalando/postgres-operator
|
||||
|
||||
RUN go clean -cache -modcache
|
||||
RUN go mod vendor \
|
||||
&& CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o build/postgres-operator -v -ldflags "-X=main.version=${VERSION}" cmd/main.go
|
||||
|
||||
ARG BASE_IMAGE
|
||||
FROM --platform=$TARGETPLATFORM ${BASE_IMAGE}
|
||||
LABEL maintainer="Team ACID @ Zalando <team-acid@zalando.de>"
|
||||
LABEL org.opencontainers.image.source="https://github.com/zalando/postgres-operator"
|
||||
|
||||
# We need root certificates to deal with teams api over https
|
||||
RUN apk --no-cache add curl
|
||||
RUN apk --no-cache add ca-certificates
|
||||
RUN apk -U upgrade --no-cache \
|
||||
&& apk add --no-cache curl ca-certificates
|
||||
|
||||
COPY build/* /
|
||||
COPY --from=builder /go/src/github.com/zalando/postgres-operator/build/* /
|
||||
|
||||
RUN addgroup -g 1000 pgo
|
||||
RUN adduser -D -u 1000 -G pgo -g 'Postgres Operator' pgo
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
#!/bin/bash
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
arch=$(dpkg --print-architecture)
|
||||
|
||||
set -ex
|
||||
|
||||
# Install dependencies
|
||||
|
||||
apt-get update
|
||||
apt-get install -y wget
|
||||
|
||||
(
|
||||
cd /tmp
|
||||
wget -q "https://storage.googleapis.com/golang/go1.26.4.linux-${arch}.tar.gz" -O go.tar.gz
|
||||
tar -xf go.tar.gz
|
||||
mv go /usr/local
|
||||
ln -s /usr/local/go/bin/go /usr/bin/go
|
||||
go version
|
||||
)
|
||||
|
||||
# Build
|
||||
|
||||
export PATH="$PATH:$HOME/go/bin"
|
||||
export GOPATH="$HOME/go"
|
||||
mkdir -p build
|
||||
|
||||
go clean -cache -modcache
|
||||
go mod vendor
|
||||
CGO_ENABLED=0 go build -o build/postgres-operator -v -ldflags "$OPERATOR_LDFLAGS" cmd/main.go
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
#! /usr/bin/env bash
|
||||
|
||||
# enable unofficial bash strict mode
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
ALL_DB_SIZE_QUERY="select sum(pg_database_size(datname)::numeric) from pg_database;"
|
||||
PG_BIN=$PG_DIR/$PG_VERSION/bin
|
||||
DUMP_SIZE_COEFF=5
|
||||
ERRORCOUNT=0
|
||||
|
||||
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
|
||||
K8S_API_URL=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1
|
||||
CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||
|
||||
function estimate_size {
|
||||
"$PG_BIN"/psql -tqAc "${ALL_DB_SIZE_QUERY}"
|
||||
}
|
||||
|
||||
function dump {
|
||||
# settings are taken from the environment
|
||||
"$PG_BIN"/pg_dumpall
|
||||
}
|
||||
|
||||
function compress {
|
||||
pigz
|
||||
}
|
||||
|
||||
function aws_upload {
|
||||
declare -r EXPECTED_SIZE="$1"
|
||||
|
||||
# mimic bucket setup from Spilo
|
||||
# to keep logical backups at the same path as WAL
|
||||
# NB: $LOGICAL_BACKUP_S3_BUCKET_SCOPE_SUFFIX already contains the leading "/" when set by the Postgres Operator
|
||||
PATH_TO_BACKUP=s3://$LOGICAL_BACKUP_S3_BUCKET"/spilo/"$SCOPE$LOGICAL_BACKUP_S3_BUCKET_SCOPE_SUFFIX"/logical_backups/"$(date +%s).sql.gz
|
||||
|
||||
args=()
|
||||
|
||||
[[ ! -z "$EXPECTED_SIZE" ]] && args+=("--expected-size=$EXPECTED_SIZE")
|
||||
[[ ! -z "$LOGICAL_BACKUP_S3_ENDPOINT" ]] && args+=("--endpoint-url=$LOGICAL_BACKUP_S3_ENDPOINT")
|
||||
[[ ! -z "$LOGICAL_BACKUP_S3_REGION" ]] && args+=("--region=$LOGICAL_BACKUP_S3_REGION")
|
||||
[[ ! -z "$LOGICAL_BACKUP_S3_SSE" ]] && args+=("--sse=$LOGICAL_BACKUP_S3_SSE")
|
||||
|
||||
aws s3 cp - "$PATH_TO_BACKUP" "${args[@]//\'/}"
|
||||
}
|
||||
|
||||
function gcs_upload {
|
||||
PATH_TO_BACKUP=gs://$LOGICAL_BACKUP_S3_BUCKET"/spilo/"$SCOPE$LOGICAL_BACKUP_S3_BUCKET_SCOPE_SUFFIX"/logical_backups/"$(date +%s).sql.gz
|
||||
|
||||
gsutil -o Credentials:gs_service_key_file=$LOGICAL_BACKUP_GOOGLE_APPLICATION_CREDENTIALS cp - "$PATH_TO_BACKUP"
|
||||
}
|
||||
|
||||
function upload {
|
||||
case $LOGICAL_BACKUP_PROVIDER in
|
||||
"gcs")
|
||||
gcs_upload
|
||||
;;
|
||||
*)
|
||||
aws_upload $(($(estimate_size) / DUMP_SIZE_COEFF))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function get_pods {
|
||||
declare -r SELECTOR="$1"
|
||||
|
||||
curl "${K8S_API_URL}/namespaces/${POD_NAMESPACE}/pods?$SELECTOR" \
|
||||
--cacert $CERT \
|
||||
-H "Authorization: Bearer ${TOKEN}" | jq .items[].status.podIP -r
|
||||
}
|
||||
|
||||
function get_current_pod {
|
||||
curl "${K8S_API_URL}/namespaces/${POD_NAMESPACE}/pods?fieldSelector=metadata.name%3D${HOSTNAME}" \
|
||||
--cacert $CERT \
|
||||
-H "Authorization: Bearer ${TOKEN}"
|
||||
}
|
||||
|
||||
declare -a search_strategy=(
|
||||
list_all_replica_pods_current_node
|
||||
list_all_replica_pods_any_node
|
||||
get_master_pod
|
||||
)
|
||||
|
||||
function list_all_replica_pods_current_node {
|
||||
get_pods "labelSelector=${CLUSTER_NAME_LABEL}%3D${SCOPE},spilo-role%3Dreplica&fieldSelector=spec.nodeName%3D${CURRENT_NODENAME}" | head -n 1
|
||||
}
|
||||
|
||||
function list_all_replica_pods_any_node {
|
||||
get_pods "labelSelector=${CLUSTER_NAME_LABEL}%3D${SCOPE},spilo-role%3Dreplica" | head -n 1
|
||||
}
|
||||
|
||||
function get_master_pod {
|
||||
get_pods "labelSelector=${CLUSTER_NAME_LABEL}%3D${SCOPE},spilo-role%3Dmaster" | head -n 1
|
||||
}
|
||||
|
||||
CURRENT_NODENAME=$(get_current_pod | jq .items[].spec.nodeName --raw-output)
|
||||
export CURRENT_NODENAME
|
||||
|
||||
for search in "${search_strategy[@]}"; do
|
||||
|
||||
PGHOST=$(eval "$search")
|
||||
export PGHOST
|
||||
|
||||
if [ -n "$PGHOST" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
set -x
|
||||
dump | compress | upload
|
||||
[[ ${PIPESTATUS[0]} != 0 || ${PIPESTATUS[1]} != 0 || ${PIPESTATUS[2]} != 0 ]] && (( ERRORCOUNT += 1 ))
|
||||
set +x
|
||||
|
||||
exit $ERRORCOUNT
|
||||
|
|
@ -3,6 +3,40 @@
|
|||
Learn how to configure and manage the Postgres Operator in your Kubernetes (K8s)
|
||||
environment.
|
||||
|
||||
## CRD registration and validation
|
||||
|
||||
On startup, the operator will try to register the necessary
|
||||
[CustomResourceDefinitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions)
|
||||
`Postgresql` and `OperatorConfiguration`. The latter will only get created if
|
||||
the `POSTGRES_OPERATOR_CONFIGURATION_OBJECT` [environment variable](https://github.com/zalando/postgres-operator/blob/master/manifests/postgres-operator.yaml#L36)
|
||||
is set in the deployment yaml and is not empty. If the CRDs already exists they
|
||||
will only be patched. If you do not wish the operator to create or update the
|
||||
CRDs set `enable_crd_registration` config option to `false`.
|
||||
|
||||
CRDs are defined with a `openAPIV3Schema` structural schema against which new
|
||||
manifests of [`postgresql`](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresql.crd.yaml) or [`OperatorConfiguration`](https://github.com/zalando/postgres-operator/blob/master/manifests/operatorconfiguration.crd.yaml)
|
||||
resources will be validated. On creation you can bypass the validation with
|
||||
`kubectl create --validate=false`.
|
||||
|
||||
By default, the operator will register the CRDs in the `all` category so
|
||||
that resources are listed on `kubectl get all` commands. The `crd_categories`
|
||||
config option allows for customization of categories.
|
||||
|
||||
## Upgrading the operator
|
||||
|
||||
The Postgres Operator is upgraded by changing the docker image within the
|
||||
deployment. Before doing so, it is recommended to check the release notes
|
||||
for new configuration options or changed behavior you might want to reflect
|
||||
in the ConfigMap or config CRD. E.g. a new feature might get introduced which
|
||||
is enabled or disabled by default and you want to change it to the opposite
|
||||
with the corresponding flag option.
|
||||
|
||||
When using helm, be aware that installing the new chart will not update the
|
||||
`Postgresql` and `OperatorConfiguration` CRD. Make sure to update them before
|
||||
with the provided manifests in the `crds` folder. Otherwise, you might face
|
||||
errors about new Postgres manifest or configuration options being unknown
|
||||
to the CRD schema validation.
|
||||
|
||||
## Minor and major version upgrade
|
||||
|
||||
Minor version upgrades for PostgreSQL are handled via updating the Spilo Docker
|
||||
|
|
@ -29,14 +63,20 @@ the `PGVERSION` environment variable is set for the database pods. Since
|
|||
`v1.6.0` the related option `enable_pgversion_env_var` is enabled by default.
|
||||
|
||||
In-place major version upgrades can be configured to be executed by the
|
||||
operator with the `major_version_upgrade_mode` option. By default it is set
|
||||
to `off` which means the cluster version will not change when increased in
|
||||
the manifest. Still, a rolling update would be triggered updating the
|
||||
`PGVERSION` variable. But Spilo's [`configure_spilo`](https://github.com/zalando/spilo/blob/master/postgres-appliance/scripts/configure_spilo.py)
|
||||
script will notice the version mismatch and start the old version again.
|
||||
operator with the `major_version_upgrade_mode` option. By default, it is
|
||||
enabled (mode: `manual`). In any case, altering the version in the manifest
|
||||
will update the desired `PGVERSION`. If `maintenanceWindows` are configured,
|
||||
major-version-related pod rotation is deferred until the next maintenance
|
||||
window. Without maintenance windows, the operator will trigger a rolling
|
||||
update of pods to apply the new `PGVERSION`.
|
||||
Spilo's [`configure_spilo`](https://github.com/zalando/spilo/blob/master/postgres-appliance/scripts/configure_spilo.py)
|
||||
script will notice the version mismatch but start the current version again.
|
||||
|
||||
In this scenario the major version could then be run by a user from within the
|
||||
master pod. Exec into the container and run:
|
||||
Next, the operator would call an updage script inside Spilo. When automatic
|
||||
upgrades are disabled (mode: `off`) the upgrade could still be run by a user
|
||||
from within the primary pod. This gives you full control about the point in
|
||||
time when the upgrade can be started (check also maintenance windows below).
|
||||
Exec into the container and run:
|
||||
```bash
|
||||
python3 /scripts/inplace_upgrade.py N
|
||||
```
|
||||
|
|
@ -45,32 +85,33 @@ The upgrade is usually fast, well under one minute for most DBs. Note, that
|
|||
changes become irrevertible once `pg_upgrade` is called. To understand the
|
||||
upgrade procedure, refer to the [corresponding PR in Spilo](https://github.com/zalando/spilo/pull/488).
|
||||
|
||||
When `major_version_upgrade_mode` is set to `manual` the operator will run
|
||||
the upgrade script for you after the manifest is updated and pods are rotated.
|
||||
When `major_version_upgrade_mode` is set to `full` the operator will compare
|
||||
the version in the manifest with the configured `minimal_major_version`. If it
|
||||
is lower the operator would start an automatic upgrade as described above. The
|
||||
configured `major_target_version` will be used as the new version. This option
|
||||
can be useful if you have to get rid of outdated major versions in your fleet.
|
||||
Please note, that the operator does not patch the version in the manifest.
|
||||
Thus, the `full` mode can create drift between desired and actual state.
|
||||
|
||||
## CRD Validation
|
||||
### Upgrade during maintenance windows
|
||||
|
||||
[CustomResourceDefinitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions)
|
||||
will be registered with schema validation by default when the operator is
|
||||
deployed. The `OperatorConfiguration` CRD will only get created if the
|
||||
`POSTGRES_OPERATOR_CONFIGURATION_OBJECT` [environment variable](../manifests/postgres-operator.yaml#L36)
|
||||
in the deployment yaml is set and not empty.
|
||||
When `maintenanceWindows` are defined in the Postgres manifest or in the global
|
||||
config the operator will trigger major-version-related pod rotation and the
|
||||
major version upgrade only during these periods. Make sure they are at least
|
||||
twice as long as your configured `resync_period` to guarantee that operator
|
||||
actions can be triggered.
|
||||
|
||||
When submitting manifests of [`postgresql`](../manifests/postgresql.crd.yaml) or
|
||||
[`OperatorConfiguration`](../manifests/operatorconfiguration.crd.yaml) custom
|
||||
resources with kubectl, validation can be bypassed with `--validate=false`. The
|
||||
operator can also be configured to not register CRDs with validation on `ADD` or
|
||||
`UPDATE` events. Running instances are not affected when enabling the validation
|
||||
afterwards unless the manifests is not changed then. Note, that the provided CRD
|
||||
manifests contain the validation for users to understand what schema is
|
||||
enforced.
|
||||
### Upgrade annotations
|
||||
|
||||
Once the validation is enabled it can only be disabled manually by editing or
|
||||
patching the CRD manifest:
|
||||
When an upgrade is executed, the operator sets an annotation in the PostgreSQL
|
||||
resource, either `last-major-upgrade-success` if the upgrade succeeds, or
|
||||
`last-major-upgrade-failure` if it fails. The value of the annotation is a
|
||||
timestamp indicating when the upgrade occurred.
|
||||
|
||||
```bash
|
||||
kubectl patch crd postgresqls.acid.zalan.do -p '{"spec":{"validation": null}}'
|
||||
```
|
||||
If a PostgreSQL resource contains a failure annotation, the operator will not
|
||||
attempt to retry the upgrade during a sync event. To remove the failure
|
||||
annotation, you can revert the PostgreSQL version back to the current version.
|
||||
This action will trigger the removal of the failure annotation.
|
||||
|
||||
## Non-default cluster domain
|
||||
|
||||
|
|
@ -94,7 +135,7 @@ kubectl config set-context $(kubectl config current-context) --namespace=test
|
|||
All subsequent `kubectl` commands will work with the `test` namespace. The
|
||||
operator will run in this namespace and look up needed resources - such as its
|
||||
ConfigMap - there. Please note that the namespace for service accounts and
|
||||
cluster role bindings in [operator RBAC rules](../manifests/operator-service-account-rbac.yaml)
|
||||
cluster role bindings in [operator RBAC rules](https://github.com/zalando/postgres-operator/blob/master/manifests/operator-service-account-rbac.yaml)
|
||||
needs to be adjusted to the non-default value.
|
||||
|
||||
### Specify the namespace to watch
|
||||
|
|
@ -105,9 +146,9 @@ clusters in the namespace such as "increase the number of Postgres replicas to
|
|||
|
||||
By default, the operator watches the namespace it is deployed to. You can
|
||||
change this by setting the `WATCHED_NAMESPACE` var in the `env` section of the
|
||||
[operator deployment](../manifests/postgres-operator.yaml) manifest or by
|
||||
[operator deployment](https://github.com/zalando/postgres-operator/blob/master/manifests/postgres-operator.yaml) manifest or by
|
||||
altering the `watched_namespace` field in the operator
|
||||
[configuration](../manifests/postgresql-operator-default-configuration.yaml#L49).
|
||||
[configuration](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresql-operator-default-configuration.yaml#L49).
|
||||
In the case both are set, the env var takes the precedence. To make the
|
||||
operator listen to all namespaces, explicitly set the field/env var to "`*`".
|
||||
|
||||
|
|
@ -128,7 +169,7 @@ But, it is also possible to define ownership between operator instances and
|
|||
Postgres clusters running all in the same namespace or K8s cluster without
|
||||
interfering.
|
||||
|
||||
First, define the [`CONTROLLER_ID`](../../manifests/postgres-operator.yaml#L38)
|
||||
First, define the [`CONTROLLER_ID`](https://github.com/zalando/postgres-operator/blob/master/manifests/postgres-operator.yaml#L38)
|
||||
environment variable in the operator deployment manifest. Then specify the ID
|
||||
in every Postgres cluster manifest you want this operator to watch using the
|
||||
`"acid.zalan.do/controller"` annotation:
|
||||
|
|
@ -157,16 +198,28 @@ from numerous escape characters in the latter log entry, view it in CLI with
|
|||
`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.
|
||||
The StatefulSet is replaced if the following properties change:
|
||||
|
||||
- annotations
|
||||
- volumeClaimTemplates
|
||||
- template volumes
|
||||
|
||||
The StatefulSet is replaced and a rolling updates is triggered if the following
|
||||
properties differ between the old and new state:
|
||||
|
||||
- container name, ports, image, resources, env, envFrom, securityContext and volumeMounts
|
||||
- template labels, annotations, service account, securityContext, affinity, priority class and termination grace period
|
||||
|
||||
Note that, changes in `SPILO_CONFIGURATION` env variable under `bootstrap.dcs`
|
||||
path are ignored for the diff. They will be applied through Patroni's rest api
|
||||
interface, following a restart of all instances.
|
||||
|
||||
The operator also support lazy updates of the Spilo image. In this case the
|
||||
StatefulSet is only updated, 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.
|
||||
|
||||
## Delete protection via annotations
|
||||
|
||||
|
|
@ -203,9 +256,9 @@ configuration:
|
|||
|
||||
Now, every cluster manifest must contain the configured annotation keys to
|
||||
trigger the delete process when running `kubectl delete pg`. Note, that the
|
||||
`Postgresql` resource would still get deleted as K8s' API server does not
|
||||
block it. Only the operator logs will tell, that the delete criteria wasn't
|
||||
met.
|
||||
`Postgresql` resource would still get deleted because the operator does not
|
||||
instruct K8s' API server to block it. Only the operator logs will tell, that
|
||||
the delete criteria was not met.
|
||||
|
||||
**cluster manifest**
|
||||
|
||||
|
|
@ -223,15 +276,68 @@ spec:
|
|||
|
||||
In case, the resource has been deleted accidentally or the annotations were
|
||||
simply forgotten, it's safe to recreate the cluster with `kubectl create`.
|
||||
Existing Postgres cluster are not replaced by the operator. But, as the
|
||||
original cluster still exists the status will show `CreateFailed` at first.
|
||||
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.
|
||||
Existing Postgres cluster are not replaced by the operator. But, when the
|
||||
original cluster still exists the status will be `CreateFailed` at first. On
|
||||
the next sync event it should change to `Running`. However, because it is in
|
||||
fact a new resource for K8s, the UID and therefore, the backup path to S3,
|
||||
will differ and trigger a rolling update of the pods.
|
||||
|
||||
## Owner References and Finalizers
|
||||
|
||||
The Postgres Operator can set [owner references](https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/) to most of a cluster's child resources to improve
|
||||
monitoring with GitOps tools and enable cascading deletes. There are two
|
||||
exceptions:
|
||||
|
||||
* Persistent Volume Claims, because they are handled by the [PV Reclaim Policy]https://kubernetes.io/docs/tasks/administer-cluster/change-pv-reclaim-policy/ of the Stateful Set
|
||||
* Cross-namespace secrets, because owner references are not allowed across namespaces by design
|
||||
|
||||
The operator would clean these resources up with its regular delete loop
|
||||
unless they got synced correctly. If for some reason the initial cluster sync
|
||||
fails, e.g. after a cluster creation or operator restart, a deletion of the
|
||||
cluster manifest might leave orphaned resources behind which the user has to
|
||||
clean up manually.
|
||||
|
||||
Another option is to enable finalizers which first ensures the deletion of all
|
||||
child resources before the cluster manifest gets removed. There is a trade-off
|
||||
though: The deletion is only performed after the next two operator SYNC cycles
|
||||
with the first one setting a `deletionTimestamp` and the latter reacting to it.
|
||||
The final removal of the custom resource will add a DELETE event to the worker
|
||||
queue but the child resources are already gone at this point. If you do not
|
||||
desire this behavior consider enabling owner references instead.
|
||||
|
||||
**postgres-operator ConfigMap**
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: postgres-operator
|
||||
data:
|
||||
enable_finalizers: "false"
|
||||
enable_owner_references: "true"
|
||||
```
|
||||
|
||||
**OperatorConfiguration**
|
||||
|
||||
```yaml
|
||||
apiVersion: "acid.zalan.do/v1"
|
||||
kind: OperatorConfiguration
|
||||
metadata:
|
||||
name: postgresql-operator-configuration
|
||||
configuration:
|
||||
kubernetes:
|
||||
enable_finalizers: false
|
||||
enable_owner_references: true
|
||||
```
|
||||
|
||||
:warning: Please note, both options are disabled by default. When enabling owner
|
||||
references the operator cannot block cascading deletes, even when the [delete protection annotations](administrator.md#delete-protection-via-annotations)
|
||||
are in place. You would need an K8s admission controller that blocks the actual
|
||||
`kubectl delete` API call e.g. based on existing annotations.
|
||||
|
||||
## Role-based access control for the operator
|
||||
|
||||
The manifest [`operator-service-account-rbac.yaml`](../manifests/operator-service-account-rbac.yaml)
|
||||
The manifest [`operator-service-account-rbac.yaml`](https://github.com/zalando/postgres-operator/blob/master/manifests/operator-service-account-rbac.yaml)
|
||||
defines the service account, cluster roles and bindings needed for the operator
|
||||
to function under access control restrictions. The file also includes a cluster
|
||||
role `postgres-pod` with privileges for Patroni to watch and manage pods and
|
||||
|
|
@ -266,6 +372,103 @@ kubectl create -f manifests/user-facing-clusterroles.yaml
|
|||
It creates zalando-postgres-operator:user:view, :edit and :admin clusterroles
|
||||
that are aggregated into the K8s [default roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#default-roles-and-role-bindings).
|
||||
|
||||
For Helm deployments setting `rbac.createAggregateClusterRoles: true` adds these clusterroles to the deployment.
|
||||
|
||||
## Password rotation in K8s secrets
|
||||
|
||||
The operator regularly updates credentials in the K8s secrets if the
|
||||
`enable_password_rotation` option is set to `true` in the configuration.
|
||||
It happens only for `LOGIN` roles with an associated secret (manifest roles,
|
||||
default users from `preparedDatabases`). Furthermore, there are the following
|
||||
exceptions:
|
||||
|
||||
1. Infrastructure role secrets since rotation should happen by the infrastructure.
|
||||
2. Team API roles that connect via OAuth2 and JWT token (no secrets to these roles anyway).
|
||||
3. Database owners since ownership on database objects can not be inherited.
|
||||
4. System users such as `postgres`, `standby` and `pooler` user.
|
||||
|
||||
The interval of days can be set with `password_rotation_interval` (default
|
||||
`90` = 90 days, minimum 1). On each rotation the user name and password values
|
||||
are replaced in the K8s secret. They belong to a newly created user named after
|
||||
the original role plus rotation date in YYMMDD format. All privileges are
|
||||
inherited meaning that migration scripts should still grant and revoke rights
|
||||
against the original role. The timestamp of the next rotation (in RFC 3339
|
||||
format, UTC timezone) is written to the secret as well. Note, if the rotation
|
||||
interval is decreased it is reflected in the secrets only if the next rotation
|
||||
date is more days away than the new length of the interval.
|
||||
|
||||
Pods still using the previous secret values which they keep in memory continue
|
||||
to connect to the database since the password of the corresponding user is not
|
||||
replaced. However, a retention policy can be configured for users created by
|
||||
the password rotation feature with `password_rotation_user_retention`. The
|
||||
operator will ensure that this period is at least twice as long as the
|
||||
configured rotation interval, hence the default of `180` = 180 days. When
|
||||
the creation date of a rotated user is older than the retention period it
|
||||
might not get removed immediately. Only on the next user rotation it is checked
|
||||
if users can get removed. Therefore, you might want to configure the retention
|
||||
to be a multiple of the rotation interval.
|
||||
|
||||
### Password rotation for single users
|
||||
|
||||
From the configuration, password rotation is enabled for all secrets with the
|
||||
mentioned exceptions. If you wish to first test rotation for a single user (or
|
||||
just have it enabled only for a few secrets) you can specify it in the cluster
|
||||
manifest. The rotation and retention intervals can only be configured globally.
|
||||
|
||||
```
|
||||
spec:
|
||||
usersWithSecretRotation:
|
||||
- foo_user
|
||||
- bar_reader_user
|
||||
```
|
||||
|
||||
### Password replacement without extra users
|
||||
|
||||
For some use cases where the secret is only used rarely - think of a `flyway`
|
||||
user running a migration script on pod start - we do not need to create extra
|
||||
database users but can replace only the password in the K8s secret. This type
|
||||
of rotation cannot be configured globally but specified in the cluster
|
||||
manifest:
|
||||
|
||||
```
|
||||
spec:
|
||||
usersWithInPlaceSecretRotation:
|
||||
- flyway
|
||||
- bar_owner_user
|
||||
```
|
||||
|
||||
This would be the recommended option to enable rotation in secrets of database
|
||||
owners, but only if they are not used as application users for regular read
|
||||
and write operations.
|
||||
|
||||
### Ignore rotation for certain users
|
||||
|
||||
If you wish to globally enable password rotation but need certain users to
|
||||
opt out from it there are two ways. First, you can remove the user from the
|
||||
manifest's `users` section. The corresponding secret to this user will no
|
||||
longer be synced by the operator then.
|
||||
|
||||
Secondly, if you want the operator to continue syncing the secret (e.g. to
|
||||
recreate if it got accidentally removed) but cannot allow it being rotated,
|
||||
add the user to the following list in your manifest:
|
||||
|
||||
```
|
||||
spec:
|
||||
usersIgnoringSecretRotation:
|
||||
- bar_user
|
||||
```
|
||||
|
||||
### Turning off password rotation
|
||||
|
||||
When password rotation is turned off again the operator will check if the
|
||||
`username` value in the secret matches the original username and replace it
|
||||
with the latter. A new password is assigned and the `nextRotation` field is
|
||||
cleared. A final lookup for child (rotation) users to be removed is done but
|
||||
they will only be dropped if the retention policy allows for it. This is to
|
||||
avoid sudden connection issues in pods which still use credentials of these
|
||||
users in memory. You have to remove these child users manually or re-enable
|
||||
password rotation with smaller interval so they get cleaned up.
|
||||
|
||||
## Use taints and tolerations for dedicated PostgreSQL nodes
|
||||
|
||||
To ensure Postgres pods are running on nodes without any other application pods,
|
||||
|
|
@ -312,6 +515,81 @@ master pods from being evicted by the K8s runtime. To prevent eviction
|
|||
completely, specify the toleration by leaving out the `tolerationSeconds` value
|
||||
(similar to how Kubernetes' own DaemonSets are configured)
|
||||
|
||||
## Node readiness labels
|
||||
|
||||
The operator can watch on certain node labels to detect e.g. the start of a
|
||||
Kubernetes cluster upgrade procedure and move master pods off the nodes to be
|
||||
decommissioned. Key-value pairs for these node readiness labels can be
|
||||
specified in the configuration (option name is in singular form):
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: postgres-operator
|
||||
data:
|
||||
node_readiness_label: "status1:ready,status2:ready"
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: "acid.zalan.do/v1"
|
||||
kind: OperatorConfiguration
|
||||
metadata:
|
||||
name: postgresql-configuration
|
||||
configuration:
|
||||
kubernetes:
|
||||
node_readiness_label:
|
||||
status1: ready
|
||||
status2: ready
|
||||
```
|
||||
|
||||
The operator will create a `nodeAffinity` on the pods. This makes the
|
||||
`node_readiness_label` option the global configuration for defining node
|
||||
affinities for all Postgres clusters. You can have both, cluster-specific and
|
||||
global affinity, defined and they will get merged on the pods. If
|
||||
`node_readiness_label_merge` is configured to `"AND"` the node readiness
|
||||
affinity will end up under the same `matchExpressions` section(s) from the
|
||||
manifest affinity.
|
||||
|
||||
```yaml
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: environment
|
||||
operator: In
|
||||
values:
|
||||
- pci
|
||||
- key: status1
|
||||
operator: In
|
||||
values:
|
||||
- ready
|
||||
- key: status2
|
||||
...
|
||||
```
|
||||
|
||||
If `node_readiness_label_merge` is set to `"OR"` (default) the readiness label
|
||||
affinity will be appended with its own expressions block:
|
||||
|
||||
```yaml
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: environment
|
||||
...
|
||||
- matchExpressions:
|
||||
- key: storage
|
||||
...
|
||||
- matchExpressions:
|
||||
- key: status1
|
||||
...
|
||||
- key: status2
|
||||
...
|
||||
```
|
||||
|
||||
## Enable pod anti affinity
|
||||
|
||||
To ensure Postgres pods are running on different topologies, you can use
|
||||
|
|
@ -341,26 +619,41 @@ configuration:
|
|||
enable_pod_antiaffinity: true
|
||||
```
|
||||
|
||||
By default the type of pod anti affinity is `requiredDuringSchedulingIgnoredDuringExecution`,
|
||||
you can switch to `preferredDuringSchedulingIgnoredDuringExecution` by setting `pod_antiaffinity_preferred_during_scheduling: true`.
|
||||
|
||||
By default the topology key for the pod anti affinity is set to
|
||||
`kubernetes.io/hostname`, you can set another topology key e.g.
|
||||
`failure-domain.beta.kubernetes.io/zone`. See [built-in node labels](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#interlude-built-in-node-labels) for available topology keys.
|
||||
|
||||
## Pod Disruption Budget
|
||||
## Pod Disruption Budgets
|
||||
|
||||
By default the operator uses a PodDisruptionBudget (PDB) to protect the cluster
|
||||
from voluntarily disruptions and hence unwanted DB downtime. The `MinAvailable`
|
||||
parameter of the PDB is set to `1` which prevents killing masters in single-node
|
||||
clusters and/or the last remaining running instance in a multi-node cluster.
|
||||
By default the operator creates two PodDisruptionBudgets (PDB) to protect the cluster
|
||||
from voluntarily disruptions and hence unwanted DB downtime: so-called primary PDB and
|
||||
and PDB for critical operations.
|
||||
|
||||
### Primary PDB
|
||||
The `MinAvailable` parameter of this PDB is set to `1` and, if `pdb_master_label_selector`
|
||||
is enabled, label selector includes `spilo-role=master` condition, which prevents killing
|
||||
masters in single-node clusters and/or the last remaining running instance in a multi-node
|
||||
cluster.
|
||||
|
||||
## PDB for critical operations
|
||||
The `MinAvailable` parameter of this PDB is equal to the `numberOfInstances` set in the
|
||||
cluster manifest, while label selector includes `critical-operation=true` condition. This
|
||||
allows to protect all pods of a cluster, given they are labeled accordingly.
|
||||
For example, Operator labels all Spilo pods with `critical-operation=true` during the major
|
||||
version upgrade run. You may want to protect cluster pods during other critical operations
|
||||
by assigning the label to pods yourself or using other means of automation.
|
||||
|
||||
The PDB is only relaxed in two scenarios:
|
||||
|
||||
* If a cluster is scaled down to `0` instances (e.g. for draining nodes)
|
||||
* If the PDB is disabled in the configuration (`enable_pod_disruption_budget`)
|
||||
|
||||
The PDB is still in place having `MinAvailable` set to `0`. If enabled it will
|
||||
be automatically set to `1` on scale up. Disabling PDBs helps avoiding blocking
|
||||
Kubernetes upgrades in managed K8s environments at the cost of prolonged DB
|
||||
downtime. See PR [#384](https://github.com/zalando/postgres-operator/pull/384)
|
||||
The PDBs are still in place having `MinAvailable` set to `0`. Disabling PDBs
|
||||
helps avoiding blocking Kubernetes upgrades in managed K8s environments at the
|
||||
cost of prolonged DB downtime. See PR [#384](https://github.com/zalando/postgres-operator/pull/384)
|
||||
for the use case.
|
||||
|
||||
## Add cluster-specific labels
|
||||
|
|
@ -426,15 +719,39 @@ 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 a customized Spilo image configured by extra environment variables.
|
||||
Another case could be to provide custom cloud provider or backup settings.
|
||||
The operator will assign a set of environment variables to the database pods
|
||||
that cannot be overridden to guarantee core functionality. Only variables with
|
||||
'WAL_' and 'LOG_' prefixes can be customized to allow for backup and log
|
||||
shipping to be specified differently. There are three ways to specify extra
|
||||
environment variables (or override existing ones) for database pods:
|
||||
|
||||
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](#via-configmap)
|
||||
* [Via Secret](#via-secret)
|
||||
* [Via Postgres Cluster Manifest](#via-postgres-cluster-manifest)
|
||||
|
||||
The first two options must be referenced from the operator configuration
|
||||
making them global settings for all Postgres cluster the operator watches.
|
||||
One use case is a customized Spilo image that must be configured by extra
|
||||
environment variables. Another case could be to provide custom cloud
|
||||
provider or backup settings.
|
||||
|
||||
The last options allows for specifying environment variables individual to
|
||||
every cluster via the `env` section in the manifest. For example, if you use
|
||||
individual backup locations for each of your clusters. Or you want to disable
|
||||
WAL archiving for a certain cluster by setting `WAL_S3_BUCKET`, `WAL_GS_BUCKET`
|
||||
or `AZURE_STORAGE_ACCOUNT` to an empty string.
|
||||
|
||||
The operator will give precedence to environment variables in the following
|
||||
order (e.g. a variable defined in 4. overrides a variable with the same name
|
||||
in 5.):
|
||||
|
||||
1. Assigned by the operator
|
||||
2. `env` section in cluster manifest
|
||||
3. Clone section (with WAL settings from operator config when `s3_wal_path` is empty)
|
||||
4. Standby section
|
||||
5. Pod environment secret via operator config
|
||||
6. Pod environment config map via operator config
|
||||
7. WAL and logical backup settings from operator config
|
||||
|
||||
### Via ConfigMap
|
||||
|
||||
|
|
@ -531,6 +848,29 @@ data:
|
|||
The key-value pairs of the Secret are all accessible as environment variables
|
||||
to the Postgres StatefulSet/pods.
|
||||
|
||||
### Via Postgres Cluster Manifest
|
||||
|
||||
It is possible to define environment variables directly in the Postgres cluster
|
||||
manifest to configure it individually. The variables must be listed under the
|
||||
`env` section in the same way you would do for [containers](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/).
|
||||
Global parameters served from a custom config map or secret will be overridden.
|
||||
|
||||
```yaml
|
||||
apiVersion: "acid.zalan.do/v1"
|
||||
kind: postgresql
|
||||
metadata:
|
||||
name: acid-test-cluster
|
||||
spec:
|
||||
env:
|
||||
- name: wal_s3_bucket
|
||||
value: my-custom-bucket
|
||||
- name: minio_secret_key
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: my-custom-secret
|
||||
key: minio_secret_key
|
||||
```
|
||||
|
||||
## Limiting the number of min and max instances in clusters
|
||||
|
||||
As a preventive measure, one can restrict the minimum and the maximum number of
|
||||
|
|
@ -551,17 +891,22 @@ cluster manifest. In the case any of these variables are omitted from the
|
|||
manifest, the operator configuration settings `enable_master_load_balancer` and
|
||||
`enable_replica_load_balancer` apply. Note that the operator settings affect
|
||||
all Postgresql services running in all namespaces watched by the operator.
|
||||
If load balancing is enabled two default annotations will be applied to its
|
||||
services:
|
||||
If load balancing is enabled the following default annotation will be applied to
|
||||
its services:
|
||||
|
||||
- `external-dns.alpha.kubernetes.io/hostname` with the value defined by the
|
||||
operator configs `master_dns_name_format` and `replica_dns_name_format`.
|
||||
This value can't be overwritten. If any changing in its value is needed, it
|
||||
MUST be done changing the DNS format operator config parameters; and
|
||||
- `service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout` with
|
||||
a default value of "3600". This value can be overwritten with the operator
|
||||
config parameter `custom_service_annotations` or the cluster parameter
|
||||
`serviceAnnotations`.
|
||||
|
||||
There are multiple options to specify service annotations that will be merged
|
||||
with each other and override in the following order (where latter take
|
||||
precedence):
|
||||
|
||||
1. Default annotations if LoadBalancer is enabled
|
||||
2. Globally configured `custom_service_annotations`
|
||||
3. `serviceAnnotations` specified in the cluster manifest
|
||||
4. `masterServiceAnnotations` and `replicaServiceAnnotations` specified in the cluster manifest
|
||||
|
||||
To limit the range of IP addresses that can reach a load balancer, specify the
|
||||
desired ranges in the `allowedSourceRanges` field (applies to both master and
|
||||
|
|
@ -575,6 +920,49 @@ lead to K8s removing this field from the manifest due to its
|
|||
Then the resultant manifest will not contain the necessary change, and the
|
||||
operator will respectively do nothing with the existing source ranges.
|
||||
|
||||
Load balancer services can also be enabled for the [connection pooler](user.md#connection-pooler)
|
||||
pods with manifest flags `enableMasterPoolerLoadBalancer` and/or
|
||||
`enableReplicaPoolerLoadBalancer` or in the operator configuration with
|
||||
`enable_master_pooler_load_balancer` and/or `enable_replica_pooler_load_balancer`.
|
||||
For the `external-dns.alpha.kubernetes.io/hostname` annotation the `-pooler`
|
||||
suffix will be appended to the cluster name used in the template which is
|
||||
defined in `master|replica_dns_name_format`.
|
||||
|
||||
## Node Ports
|
||||
|
||||
Alternatively to Load Balancers Node Ports can be used. Kubernetes services with type
|
||||
`NodePort` redirect traffic from a specified port on your kubernetes nodes to your service.
|
||||
To expose your services to an external network with NodePorts you can set `enableMasterNodePort` and/or `enableReplicaNodePort` to `true`
|
||||
in your cluster manifest. In the case any of these variables are omitted from the manifest, the operator configuration settings `enable_master_node_port` and `enable_replica_node_port` apply.
|
||||
Note that the operator settings affect all Postgresql services running in all namespaces watched
|
||||
by the operator.
|
||||
|
||||
**Enabling a NodePort configuration will override the corresponding LoadBalancer configuration.**
|
||||
|
||||
There are multiple options to specify service annotations that will be merged
|
||||
with each other and override in the following order (where latter take
|
||||
precedence):
|
||||
|
||||
1. Globally configured `custom_service_annotations`
|
||||
2. `serviceAnnotations` specified in the cluster manifest
|
||||
3. `masterServiceAnnotations` and `replicaServiceAnnotations` specified in the cluster manifest
|
||||
|
||||
Load-Balancer specific annotations are not applied.
|
||||
|
||||
Node port services can also be configured for the [connection pooler](user.md#connection-pooler) pods
|
||||
with the manifest flags `enableMasterPoolerNodePort` and/or `enableReplicaPoolerNodePort` or in the operator configuration with `enable_master_pooler_node_port`
|
||||
and/or `enable_replica_pooler_node_port`.
|
||||
|
||||
To configure which ports Kubernetes should use for your NodePort service you can configure ports in your cluster manifest
|
||||
for each type:
|
||||
|
||||
- masterNodePort
|
||||
- masterPoolerNodePort
|
||||
- replicaNodePort
|
||||
- replicaPoolerNodePort
|
||||
|
||||
When not defined or set to 0 kubernetes will choose a port for you from [your kubernetes cluster's configured range](https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport).
|
||||
|
||||
## Running periodic 'autorepair' scans of K8s objects
|
||||
|
||||
The Postgres Operator periodically scans all K8s objects belonging to each
|
||||
|
|
@ -663,6 +1051,12 @@ if it ends up in your specified WAL backup path:
|
|||
envdir "/run/etc/wal-e.d/env" /scripts/postgres_backup.sh "/home/postgres/pgdata/pgroot/data"
|
||||
```
|
||||
|
||||
You can also check if Spilo is able to find any backups:
|
||||
|
||||
```bash
|
||||
envdir "/run/etc/wal-e.d/env" wal-g backup-list
|
||||
```
|
||||
|
||||
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
|
||||
|
|
@ -730,14 +1124,99 @@ 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
|
||||
The operator sets the prefix to an empty string so that spilo will generate it
|
||||
from the configured `WAL_S3_BUCKET`.
|
||||
|
||||
:warning: When you overwrite the configuration by defining `WAL_S3_BUCKET` in
|
||||
the [pod_environment_configmap](#custom-pod-environment-variables) you have
|
||||
to set `WAL_BUCKET_SCOPE_PREFIX = ""`, too. Otherwise Spilo will not find
|
||||
the physical backups on restore (next chapter).
|
||||
|
||||
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.
|
||||
|
||||
:warning: If both `AWS_REGION` and `AWS_ENDPOINT` or `WALE_S3_ENDPOINT` are
|
||||
defined backups with WAL-E will fail. You can fix it by switching to WAL-G
|
||||
with `USE_WALG_BACKUP: "true"`.
|
||||
|
||||
### Google Cloud Platform setup
|
||||
|
||||
To configure the operator on GCP these prerequisites that are needed:
|
||||
When using GCP, there are two authentication methods to allow the postgres
|
||||
cluster to access buckets to write WAL-E logs: Workload Identity (recommended)
|
||||
or using a GCP Service Account Key (legacy).
|
||||
|
||||
#### Workload Identity setup
|
||||
|
||||
To configure the operator on GCP using Workload Identity these prerequisites are
|
||||
needed.
|
||||
|
||||
* [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) enabled on the GKE cluster where the operator will be deployed
|
||||
* A GCP service account with the proper IAM setup to access the GCS bucket for the WAL-E logs
|
||||
* An IAM policy granting the Kubernetes service account the
|
||||
`roles/iam.workloadIdentityUser` role on the GCP service account, e.g.:
|
||||
```bash
|
||||
gcloud iam service-accounts add-iam-policy-binding <GCP_SERVICE_ACCOUNT_NAME>@<GCP_PROJECT_ID>.iam.gserviceaccount.com \
|
||||
--role roles/iam.workloadIdentityUser \
|
||||
--member "serviceAccount:PROJECT_ID.svc.id.goog[<POSTGRES_OPERATOR_NS>/postgres-pod-custom]"
|
||||
```
|
||||
|
||||
The configuration parameters that we will be using are:
|
||||
|
||||
* `wal_gs_bucket`
|
||||
|
||||
1. Create a custom Kubernetes service account to be used by Patroni running on
|
||||
the postgres cluster pods, this service account should include an annotation
|
||||
with the email address of the Google IAM service account used to communicate
|
||||
with the GCS bucket, e.g.
|
||||
|
||||
```yml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: postgres-pod-custom
|
||||
namespace: <POSTGRES_OPERATOR_NS>
|
||||
annotations:
|
||||
iam.gke.io/gcp-service-account: <GCP_SERVICE_ACCOUNT_NAME>@<GCP_PROJECT_ID>.iam.gserviceaccount.com
|
||||
```
|
||||
|
||||
2. Specify the new custom service account in your [operator parameters](./reference/operator_parameters.md)
|
||||
|
||||
If using manual deployment or kustomize, this is done by setting
|
||||
`pod_service_account_name` in your configuration file specified in the
|
||||
[postgres-operator deployment](../manifests/postgres-operator.yaml#L37)
|
||||
|
||||
If deploying the operator [using Helm](./quickstart.md#helm-chart), this can
|
||||
be specified in the chart's values file, e.g.:
|
||||
|
||||
```yml
|
||||
...
|
||||
podServiceAccount:
|
||||
name: postgres-pod-custom
|
||||
```
|
||||
|
||||
3. Setup your operator configuration values. Ensure that the operator's configuration
|
||||
is set up like the following:
|
||||
```yml
|
||||
...
|
||||
aws_or_gcp:
|
||||
# additional_secret_mount: ""
|
||||
# additional_secret_mount_path: ""
|
||||
# aws_region: eu-central-1
|
||||
# kube_iam_role: ""
|
||||
# log_s3_bucket: ""
|
||||
# wal_s3_bucket: ""
|
||||
wal_gs_bucket: "postgres-backups-bucket-28302F2" # name of bucket on where to save the WAL-E logs
|
||||
# gcp_credentials: ""
|
||||
...
|
||||
```
|
||||
|
||||
Continue to shared steps below.
|
||||
|
||||
#### GCP Service Account Key setup
|
||||
|
||||
To configure the operator on GCP using a GCP service account key these
|
||||
prerequisites 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.
|
||||
|
|
@ -770,7 +1249,7 @@ is set up like the following:
|
|||
```yml
|
||||
...
|
||||
aws_or_gcp:
|
||||
additional_secret_mount: "pgsql-wale-creds"
|
||||
additional_secret_mount: "psql-wale-creds"
|
||||
additional_secret_mount_path: "/var/secrets/google" # or where ever you want to mount the file
|
||||
# aws_region: eu-central-1
|
||||
# kube_iam_role: ""
|
||||
|
|
@ -781,7 +1260,10 @@ aws_or_gcp:
|
|||
...
|
||||
```
|
||||
|
||||
3. Setup pod environment configmap that instructs the operator to use WAL-G,
|
||||
Once you have set up authentication using one of the two methods above, continue
|
||||
with the remaining shared steps:
|
||||
|
||||
1. Setup pod environment configmap that instructs the operator to use WAL-G,
|
||||
instead of WAL-E, for backup and restore.
|
||||
```yml
|
||||
apiVersion: v1
|
||||
|
|
@ -796,7 +1278,7 @@ data:
|
|||
CLONE_USE_WALG_RESTORE: "true"
|
||||
```
|
||||
|
||||
4. Then provide this configmap in postgres-operator settings:
|
||||
2. Then provide this configmap in postgres-operator settings:
|
||||
```yml
|
||||
...
|
||||
# namespaced name of the ConfigMap with environment variables to populate on every pod
|
||||
|
|
@ -804,15 +1286,110 @@ pod_environment_configmap: "postgres-operator-system/pod-env-overrides"
|
|||
...
|
||||
```
|
||||
|
||||
### Azure setup
|
||||
|
||||
To configure the operator on Azure these prerequisites are needed:
|
||||
|
||||
* A storage account in the same region as the Kubernetes cluster.
|
||||
|
||||
The configuration parameters that we will be using are:
|
||||
|
||||
* `pod_environment_secret`
|
||||
* `wal_az_storage_account`
|
||||
|
||||
1. Generate the K8s secret resource that will contain your storage account's
|
||||
access key. You will need a copy of this secret in every namespace you want to
|
||||
create postgresql clusters.
|
||||
|
||||
The latest version of WAL-G (v1.0) supports the use of a SASS token, but you'll
|
||||
have to make due with using the primary or secondary access token until the
|
||||
version of WAL-G is updated in the postgres-operator.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: psql-backup-creds
|
||||
namespace: default
|
||||
type: Opaque
|
||||
stringData:
|
||||
AZURE_STORAGE_ACCESS_KEY: <primary or secondary access key>
|
||||
```
|
||||
|
||||
2. 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
|
||||
metadata:
|
||||
name: pod-env-overrides
|
||||
namespace: postgres-operator-system
|
||||
data:
|
||||
# Any env variable used by spilo can be added
|
||||
USE_WALG_BACKUP: "true"
|
||||
USE_WALG_RESTORE: "true"
|
||||
CLONE_USE_WALG_RESTORE: "true"
|
||||
WALG_AZ_PREFIX: "azure://container-name/$(SCOPE)/$(PGVERSION)" # Enables Azure Backups (SCOPE = Cluster name) (PGVERSION = Postgres version)
|
||||
```
|
||||
|
||||
3. Setup your operator configuration values. With the `psql-backup-creds`
|
||||
and `pod-env-overrides` resources applied to your cluster, ensure that the operator's configuration
|
||||
is set up like the following:
|
||||
```yml
|
||||
...
|
||||
kubernetes:
|
||||
pod_environment_secret: "psql-backup-creds"
|
||||
pod_environment_configmap: "postgres-operator-system/pod-env-overrides"
|
||||
aws_or_gcp:
|
||||
wal_az_storage_account: "postgresbackupsbucket28302F2" # name of storage account to save the WAL-G logs
|
||||
...
|
||||
```
|
||||
|
||||
### 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)
|
||||
[pg_basebackup](https://www.postgresql.org/docs/18/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.
|
||||
|
||||
If you need to provide a [custom clone environment](#custom-pod-environment-variables)
|
||||
copy existing variables about your setup (backup location, prefix, access
|
||||
keys etc.) and prepend the `CLONE_` prefix to get them copied to the correct
|
||||
directory within Spilo.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: postgres-pod-config
|
||||
data:
|
||||
AWS_REGION: "eu-west-1"
|
||||
AWS_ACCESS_KEY_ID: "****"
|
||||
AWS_SECRET_ACCESS_KEY: "****"
|
||||
...
|
||||
CLONE_AWS_REGION: "eu-west-1"
|
||||
CLONE_AWS_ACCESS_KEY_ID: "****"
|
||||
CLONE_AWS_SECRET_ACCESS_KEY: "****"
|
||||
...
|
||||
```
|
||||
|
||||
### Standby clusters
|
||||
|
||||
The setup for [standby clusters](user.md#setting-up-a-standby-cluster) is
|
||||
similar to cloning when they stream changes from a WAL archive (S3 or GCS).
|
||||
If you are using [additional environment variables](#custom-pod-environment-variables)
|
||||
to access your backup location you have to copy those variables and prepend
|
||||
the `STANDBY_` prefix for Spilo to find the backups and WAL files to stream.
|
||||
|
||||
Standby clusters can also stream from a remote primary cluster.
|
||||
You have to specify the host address. Port is optional and defaults to 5432.
|
||||
You can combine `standby_host` with either `s3_wal_path` or `gs_wal_path`
|
||||
for additional redundancy. Note that `s3_wal_path` and `gs_wal_path` are
|
||||
mutually exclusive. At least one of `s3_wal_path`, `gs_wal_path`, or
|
||||
`standby_host` must be specified under the `standby` top-level key.
|
||||
|
||||
## Logical backups
|
||||
|
||||
The operator can manage K8s cron jobs to run logical backups (SQL dumps) of
|
||||
|
|
@ -840,7 +1417,7 @@ 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
|
||||
2. The [example image](https://github.com/zalando/postgres-operator/blob/master/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.
|
||||
|
|
@ -859,7 +1436,11 @@ 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)
|
||||
See [example RBAC](https://github.com/zalando/postgres-operator/blob/master/manifests/operator-service-account-rbac.yaml)
|
||||
|
||||
7. Resources of the pod template in the cron job can be configured. When left
|
||||
empty [default values of spilo pods](reference/operator_parameters.md#kubernetes-resource-requests)
|
||||
will be used.
|
||||
|
||||
## Sidecars for Postgres clusters
|
||||
|
||||
|
|
@ -878,6 +1459,10 @@ configuration:
|
|||
volumeMounts:
|
||||
- mountPath: /custom-pgdata-mountpoint
|
||||
name: pgdata
|
||||
env:
|
||||
- name: "ENV_VAR_NAME"
|
||||
value: "any-k8s-env-things"
|
||||
command: ['sh', '-c', 'echo "logging" > /opt/logs.txt']
|
||||
- ...
|
||||
```
|
||||
|
||||
|
|
@ -913,11 +1498,13 @@ default. Alternatively, a list can also be passed when starting the Python
|
|||
application with the `--cluster` option.
|
||||
|
||||
The Operator API endpoint can be configured via the `OPERATOR_API_URL`
|
||||
environment variables in the [deployment manifest](../ui/manifests/deployment.yaml#L40).
|
||||
You can also expose the operator API through a [service](../manifests/api-service.yaml).
|
||||
environment variables in the [deployment manifest](https://github.com/zalando/postgres-operator/blob/master/ui/manifests/deployment.yaml#L40).
|
||||
You can also expose the operator API through a [service](https://github.com/zalando/postgres-operator/blob/master/manifests/api-service.yaml).
|
||||
Some displayed options can be disabled from UI using simple flags under the
|
||||
`OPERATOR_UI_CONFIG` field in the deployment.
|
||||
|
||||
The viewing and creation of clusters within the UI is limited to the namespace specified by the `TARGET_NAMESPACE` option. To allow the creation and viewing of clusters in all namespaces, set `TARGET_NAMESPACE` to `*`.
|
||||
|
||||
### Deploy the UI on K8s
|
||||
|
||||
Now, apply all manifests from the `ui/manifests` folder to deploy the Postgres
|
||||
|
|
@ -950,7 +1537,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.6.3 .
|
||||
docker build -t ghcr.io/zalando/postgres-operator-ui:v1.15.1 .
|
||||
|
||||
# apply UI manifests next to a running Postgres Operator
|
||||
kubectl apply -f manifests/
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ features and tests.
|
|||
|
||||
Postgres Operator is written in Go. Use the [installation instructions](https://golang.org/doc/install#install)
|
||||
if you don't have Go on your system. You won't be able to compile the operator
|
||||
with Go older than 1.15. We recommend installing [the latest one](https://golang.org/dl/).
|
||||
with Go older than 1.17. We recommend installing [the latest one](https://golang.org/dl/).
|
||||
|
||||
Go projects expect their source code and all the dependencies to be located
|
||||
under the [GOPATH](https://github.com/golang/go/wiki/GOPATH). Normally, one
|
||||
|
|
@ -16,7 +16,7 @@ under the ~/go/src sub directories.
|
|||
|
||||
Given the schema above, the Postgres Operator source code located at
|
||||
`github.com/zalando/postgres-operator` should be put at
|
||||
-`~/go/src/github.com/zalando/postgres-operator`.
|
||||
`~/go/src/github.com/zalando/postgres-operator`.
|
||||
|
||||
```bash
|
||||
export GOPATH=~/go
|
||||
|
|
@ -33,17 +33,14 @@ by setting the `GO111MODULE` environment variable to `on`. The make targets do
|
|||
this for you, so simply run
|
||||
|
||||
```bash
|
||||
make deps
|
||||
make
|
||||
```
|
||||
|
||||
This would take a while to complete. You have to redo `make deps` every time
|
||||
your dependencies list changes, i.e. after adding a new library dependency.
|
||||
|
||||
Build the operator with the `make docker` command. You may define the TAG
|
||||
variable to assign an explicit tag to your Docker image and the IMAGE to set
|
||||
the image name. By default, the tag is computed with
|
||||
`git describe --tags --always --dirty` and the image is
|
||||
`registry.opensource.zalan.do/acid/postgres-operator`
|
||||
`ghcr.io/zalando/postgres-operator`
|
||||
|
||||
```bash
|
||||
export TAG=$(git describe --tags --always --dirty)
|
||||
|
|
@ -72,22 +69,32 @@ make docker
|
|||
|
||||
# kind
|
||||
make docker
|
||||
kind load docker-image <image> --name <kind-cluster-name>
|
||||
kind load docker-image ghcr.io/zalando/postgres-operator:${TAG} --name <kind-cluster-name>
|
||||
```
|
||||
|
||||
Then create a new Postgres Operator deployment. You can reuse the provided
|
||||
manifest but replace the version and tag. Don't forget to also apply
|
||||
Then create a new Postgres Operator deployment.
|
||||
|
||||
### Deploying manually with manifests and kubectl
|
||||
|
||||
You can reuse the provided manifest but replace the version and tag. Don't forget to also apply
|
||||
configuration and RBAC manifests first, e.g.:
|
||||
|
||||
```bash
|
||||
kubectl create -f manifests/configmap.yaml
|
||||
kubectl create -f manifests/operator-service-account-rbac.yaml
|
||||
sed -e "s/\(image\:.*\:\).*$/\1$TAG/" manifests/postgres-operator.yaml | kubectl create -f -
|
||||
sed -e "s/\(image\:.*\:\).*$/\1$TAG/" -e "s/\(imagePullPolicy\:\).*$/\1 Never/" manifests/postgres-operator.yaml | kubectl create -f -
|
||||
|
||||
# check if the operator is coming up
|
||||
kubectl get pod -l name=postgres-operator
|
||||
```
|
||||
|
||||
### Deploying with Helm chart
|
||||
|
||||
Yoy can reuse the provided Helm chart to deploy local operator build with the following command:
|
||||
```bash
|
||||
helm install postgres-operator ./charts/postgres-operator --namespace zalando-operator --set image.tag=${TAG} --set image.pullPolicy=Never
|
||||
```
|
||||
|
||||
## Code generation
|
||||
|
||||
The operator employs K8s-provided code generation to obtain deep copy methods
|
||||
|
|
@ -95,6 +102,7 @@ and K8s-like APIs for its custom resource definitions, namely the
|
|||
Postgres CRD and the operator CRD. The usage of the code generation follows
|
||||
conventions from the K8s community. Relevant scripts live in the `hack`
|
||||
directory:
|
||||
|
||||
* `update-codegen.sh` triggers code generation for the APIs defined in `pkg/apis/acid.zalan.do/`,
|
||||
* `verify-codegen.sh` checks if the generated code is up-to-date (to be used within CI).
|
||||
|
||||
|
|
@ -102,6 +110,7 @@ The `/pkg/generated/` contains the resultant code. To make these scripts work,
|
|||
you may need to `export GOPATH=$(go env GOPATH)`
|
||||
|
||||
References for code generation are:
|
||||
|
||||
* [Relevant pull request](https://github.com/zalando/postgres-operator/pull/369)
|
||||
See comments there for minor issues that can sometimes broke the generation process.
|
||||
* [Code generator source code](https://github.com/kubernetes/code-generator)
|
||||
|
|
@ -208,10 +217,16 @@ dlv connect 127.0.0.1:DLV_PORT
|
|||
|
||||
## Unit tests
|
||||
|
||||
Prerequisites:
|
||||
|
||||
```bash
|
||||
make mocks
|
||||
```
|
||||
|
||||
To run all unit tests, you can simply do:
|
||||
|
||||
```bash
|
||||
go test ./pkg/...
|
||||
make test
|
||||
```
|
||||
|
||||
In case if you need to debug your unit test, it's possible to use delve:
|
||||
|
|
@ -257,17 +272,17 @@ Examples for fake K8s objects can be found in:
|
|||
|
||||
The operator provides reference end-to-end (e2e) tests to
|
||||
ensure various infrastructure parts work smoothly together. The test code is available at `e2e/tests`.
|
||||
The special `registry.opensource.zalan.do/acid/postgres-operator-e2e-tests-runner` image is used to run the tests. The container mounts the local `e2e/tests` directory at runtime, so whatever you modify in your local copy of the tests will be executed by a test runner. By maintaining a separate test runner image we avoid the need to re-build the e2e test image on every build.
|
||||
The special `ghcr.io/zalando/postgres-operator-e2e-tests-runner` image is used to run the tests. The container mounts the local `e2e/tests` directory at runtime, so whatever you modify in your local copy of the tests will be executed by a test runner. By maintaining a separate test runner image we avoid the need to re-build the e2e test image on every build.
|
||||
|
||||
Each e2e execution tests a Postgres Operator image built from the current git branch. The test
|
||||
runner creates a new local K8s cluster using [kind](https://kind.sigs.k8s.io/),
|
||||
Each e2e execution tests a Postgres Operator image built from the current git branch.
|
||||
The test runner creates a new local K8s cluster using [kind](https://kind.sigs.k8s.io/),
|
||||
utilizes provided manifest examples, and runs e2e tests contained in the `tests`
|
||||
folder. The K8s API client in the container connects to the `kind` cluster via
|
||||
the standard Docker `bridge` network. The kind cluster is deleted if tests
|
||||
finish successfully or on each new run in case it still exists.
|
||||
|
||||
End-to-end tests are executed automatically during builds (for more details,
|
||||
see the [README](../e2e/README.md) in the `e2e` folder):
|
||||
see the [README](https://github.com/zalando/postgres-operator/blob/master/e2e/README.md) in the `e2e` folder):
|
||||
|
||||
```bash
|
||||
make e2e
|
||||
|
|
@ -291,40 +306,44 @@ parameters (with exceptions for certain Patroni/Postgres options) and
|
|||
variables if you feel a per-cluster configuration is necessary.
|
||||
|
||||
Note: If one option is defined in the operator configuration and in the cluster
|
||||
[manifest](../manifests/complete-postgres-manifest.yaml), the latter takes
|
||||
[manifest](https://github.com/zalando/postgres-operator/blob/master/manifests/complete-postgres-manifest.yaml), the latter takes
|
||||
precedence.
|
||||
|
||||
### Go code
|
||||
|
||||
Update the following Go files that obtain the configuration parameter from the
|
||||
manifest files:
|
||||
* [operator_configuration_type.go](../pkg/apis/acid.zalan.do/v1/operator_configuration_type.go)
|
||||
* [operator_config.go](../pkg/controller/operator_config.go)
|
||||
* [config.go](../pkg/util/config/config.go)
|
||||
|
||||
Postgres manifest parameters are defined in the [api package](../pkg/apis/acid.zalan.do/v1/postgresql_type.go).
|
||||
The operator behavior has to be implemented at least in [k8sres.go](../pkg/cluster/k8sres.go).
|
||||
Validation of CRD parameters is controlled in [crds.go](../pkg/apis/acid.zalan.do/v1/crds.go).
|
||||
* [operator_configuration_type.go](https://github.com/zalando/postgres-operator/blob/master/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go)
|
||||
* [operator_config.go](https://github.com/zalando/postgres-operator/blob/master/pkg/controller/operator_config.go)
|
||||
* [config.go](https://github.com/zalando/postgres-operator/blob/master/pkg/util/config/config.go)
|
||||
|
||||
Postgres manifest parameters are defined in the [api package](https://github.com/zalando/postgres-operator/blob/master/pkg/apis/acid.zalan.do/v1/postgresql_type.go).
|
||||
The operator behavior has to be implemented at least in [k8sres.go](https://github.com/zalando/postgres-operator/blob/master/pkg/cluster/k8sres.go).
|
||||
Validation of CRD parameters is controlled in [crds.go](https://github.com/zalando/postgres-operator/blob/master/pkg/apis/acid.zalan.do/v1/crds.go).
|
||||
Please, reflect your changes in tests, for example in:
|
||||
* [config_test.go](../pkg/util/config/config_test.go)
|
||||
* [k8sres_test.go](../pkg/cluster/k8sres_test.go)
|
||||
* [util_test.go](../pkg/apis/acid.zalan.do/v1/util_test.go)
|
||||
|
||||
* [config_test.go](https://github.com/zalando/postgres-operator/blob/master/pkg/util/config/config_test.go)
|
||||
* [k8sres_test.go](https://github.com/zalando/postgres-operator/blob/master/pkg/cluster/k8sres_test.go)
|
||||
* [util_test.go](https://github.com/zalando/postgres-operator/blob/master/pkg/apis/acid.zalan.do/v1/util_test.go)
|
||||
|
||||
### Updating manifest files
|
||||
|
||||
For the CRD-based configuration, please update the following files:
|
||||
* the default [OperatorConfiguration](../manifests/postgresql-operator-default-configuration.yaml)
|
||||
* the CRD's [validation](../manifests/operatorconfiguration.crd.yaml)
|
||||
* the CRD's validation in the [Helm chart](../charts/postgres-operator/crds/operatorconfigurations.yaml)
|
||||
|
||||
Add new options also to the Helm chart's [values file](../charts/postgres-operator/values.yaml) file.
|
||||
* the default [OperatorConfiguration](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresql-operator-default-configuration.yaml)
|
||||
* the CRD's [validation](https://github.com/zalando/postgres-operator/blob/master/manifests/operatorconfiguration.crd.yaml)
|
||||
* the CRD's validation in the [Helm chart](https://github.com/zalando/postgres-operator/blob/master/charts/postgres-operator/crds/operatorconfigurations.yaml)
|
||||
|
||||
Add new options also to the Helm chart's [values file](https://github.com/zalando/postgres-operator/blob/master/charts/postgres-operator/values.yaml) file.
|
||||
It follows the OperatorConfiguration CRD layout. Nested values will be flattened for the ConfigMap.
|
||||
Last but no least, update the [ConfigMap](../manifests/configmap.yaml) manifest example as well.
|
||||
Last but no least, update the [ConfigMap](https://github.com/zalando/postgres-operator/blob/master/manifests/configmap.yaml) manifest example as well.
|
||||
|
||||
### Updating documentation
|
||||
|
||||
Finally, add a section for each new configuration option and/or cluster manifest
|
||||
parameter in the reference documents:
|
||||
|
||||
* [config reference](reference/operator_parameters.md)
|
||||
* [manifest reference](reference/cluster_manifest.md)
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 922 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 887 KiB |
|
|
@ -8,10 +8,10 @@ manages PostgreSQL clusters on Kubernetes (K8s):
|
|||
user submits a new manifest, the operator fetches that manifest and spawns a
|
||||
new Postgres cluster along with all necessary entities such as K8s
|
||||
StatefulSets and Postgres roles. See this
|
||||
[Postgres cluster manifest](../manifests/complete-postgres-manifest.yaml)
|
||||
[Postgres cluster manifest](https://github.com/zalando/postgres-operator/blob/master/manifests/complete-postgres-manifest.yaml)
|
||||
for settings that a manifest may contain.
|
||||
|
||||
2. The operator also watches updates to [its own configuration](../manifests/configmap.yaml)
|
||||
2. The operator also watches updates to [its own configuration](https://github.com/zalando/postgres-operator/blob/master/manifests/configmap.yaml)
|
||||
and alters running Postgres clusters if necessary. For instance, if the
|
||||
Docker image in a pod is changed, the operator carries out the rolling
|
||||
update, which means it re-spawns pods of each managed StatefulSet one-by-one
|
||||
|
|
@ -71,6 +71,8 @@ Please, report any issues discovered to https://github.com/zalando/postgres-oper
|
|||
|
||||
## Talks
|
||||
|
||||
- "Watching after your PostGIS herd" talk by Felix Kunde, FOSS4G 2021: [video](https://www.youtube.com/watch?v=T96FvjSv98A) | [slides](https://docs.google.com/presentation/d/1IICz2RsjNAcosKVGFna7io-65T2zBbGcBHFFtca24cc/edit?usp=sharing)
|
||||
|
||||
- "PostgreSQL on K8S at Zalando: Two years in production" talk by Alexander Kukushkin, FOSSDEM 2020: [video](https://fosdem.org/2020/schedule/event/postgresql_postgresql_on_k8s_at_zalando_two_years_in_production/) | [slides](https://fosdem.org/2020/schedule/event/postgresql_postgresql_on_k8s_at_zalando_two_years_in_production/attachments/slides/3883/export/events/attachments/postgresql_postgresql_on_k8s_at_zalando_two_years_in_production/slides/3883/PostgreSQL_on_K8s_at_Zalando_Two_years_in_production.pdf)
|
||||
|
||||
- "Postgres as a Service at Zalando" talk by Jan Mußler, DevOpsDays Poznań 2019: [video](https://www.youtube.com/watch?v=FiWS5m72XI8)
|
||||
|
|
@ -87,10 +89,20 @@ Please, report any issues discovered to https://github.com/zalando/postgres-oper
|
|||
|
||||
## Posts
|
||||
|
||||
- Series of blog posts on how to use the Zalando Operator, configure backups and use etcd as DCS by [thedatabaseme](https://thedatabaseme.de/tag/zalando-operator/), Mar. 2022-23.
|
||||
|
||||
- "Zalando Postgres Operator in Production: the way of Helm" by Zangir Kapishov on [medium](https://medium.com/@zkapishov/zalando-postgres-operator-in-production-the-way-of-helm-ccfd639ccb2d), Jan. 2023.
|
||||
|
||||
- "Chaos testing of a Postgres cluster managed by the Zalando Postgres Operator" by Nikolay Sivko on [coroot](https://coroot.com/blog/chaos-testing-zalando-postgres-operator), Aug. 2022.
|
||||
|
||||
- "Getting started with the Zalando Operator for PostgreSQL" by Daniel Westermann on [dbi services blog](https://www.dbi-services.com/blog/getting-started-with-the-zalando-operator-for-postgresql/), Mar. 2021.
|
||||
|
||||
- "Our experience with Postgres Operator for Kubernetes by Zalando" by Nikolay Bogdanov on [Palark blog](https://blog.palark.com/our-experience-with-postgres-operator-for-kubernetes-by-zalando/), Feb. 2021.
|
||||
|
||||
- "How to set up continuous backups and monitoring" by Pål Kristensen on [GitHub](https://github.com/zalando/postgres-operator/issues/858#issuecomment-608136253), Mar. 2020.
|
||||
|
||||
- "Postgres on Kubernetes with the Zalando operator" by Vito Botta on [has_many :code](https://vitobotta.com/2020/02/05/postgres-kubernetes-zalando-operator/), Feb. 2020.
|
||||
|
||||
- "Running PostgreSQL in Google Kubernetes Engine" by Kenneth Rørvik on [Repill Linpro](https://www.redpill-linpro.com/techblog/2019/09/28/postgres-in-kubernetes.html), Sep. 2019.
|
||||
- "Running PostgreSQL in Google Kubernetes Engine" by Kenneth Rørvik on [Repill Linpro blog](https://www.redpill-linpro.com/techblog/2019/09/28/postgres-in-kubernetes.html), Sep. 2019.
|
||||
|
||||
- "Zalando Postgres Operator: One Year Later" by Sergey Dudoladov on [Open Source Zalando](https://opensource.zalando.com/blog/2018/11/postgres-operator/), Nov. 2018
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ status page.
|
|||
Usually, the startup should only take up to 1 minute. If you feel the process
|
||||
got stuck click on the "Logs" button to inspect the operator logs. If the logs
|
||||
look fine, but the UI seems to got stuck, check if you are have configured the
|
||||
same [cluster name label](../ui/manifests/deployment.yaml#L45) like for the
|
||||
[operator](../manifests/configmap.yaml#L13).
|
||||
same [cluster name label](https://github.com/zalando/postgres-operator/blob/master/ui/manifests/deployment.yaml#L45) like for the
|
||||
[operator](https://github.com/zalando/postgres-operator/blob/master/manifests/configmap.yaml#L13).
|
||||
|
||||
From the "Status" field in the top menu you can also retrieve the logs and queue
|
||||
of each worker the operator is using. The number of concurrent workers can be
|
||||
|
|
|
|||
|
|
@ -10,17 +10,17 @@ hence set it up first. For local tests we recommend to use one of the following
|
|||
solutions:
|
||||
|
||||
* [minikube](https://github.com/kubernetes/minikube/releases), which creates a
|
||||
single-node K8s cluster inside a VM (requires KVM or VirtualBox),
|
||||
K8s cluster inside a container or VM (requires Docker, KVM, Hyper-V, HyperKit, VirtualBox, or similar),
|
||||
* [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).
|
||||
To interact with the K8s infrastructure install its CLI runtime [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-via-curl).
|
||||
|
||||
This quickstart assumes that you have started minikube or created a local kind
|
||||
cluster. Note that you can also use built-in K8s support in the Docker Desktop
|
||||
for Mac to follow the steps of this tutorial. You would have to replace
|
||||
`minikube start` and `minikube delete` with your launch actions for the Docker
|
||||
built-in K8s support.
|
||||
Desktop built-in K8s support.
|
||||
|
||||
## Configuration Options
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ The Postgres Operator can be deployed in the following ways:
|
|||
* Kustomization
|
||||
* Helm chart
|
||||
|
||||
### Manual deployment setup
|
||||
### Manual deployment setup on Kubernetes
|
||||
|
||||
The Postgres Operator can be installed simply by applying yaml manifests. Note,
|
||||
we provide the `/manifests` directory as an example only; you should consider
|
||||
|
|
@ -56,7 +56,7 @@ kubectl create -f manifests/api-service.yaml # operator API to be used by UI
|
|||
```
|
||||
|
||||
There is a [Kustomization](https://github.com/kubernetes-sigs/kustomize)
|
||||
manifest that [combines the mentioned resources](../manifests/kustomization.yaml)
|
||||
manifest that [combines the mentioned resources](https://github.com/zalando/postgres-operator/blob/master/manifests/kustomization.yaml)
|
||||
(except for the CRD) - it can be used with kubectl 1.14 or newer as easy as:
|
||||
|
||||
```bash
|
||||
|
|
@ -64,26 +64,45 @@ kubectl apply -k github.com/zalando/postgres-operator/manifests
|
|||
```
|
||||
|
||||
For convenience, we have automated starting the operator with minikube using the
|
||||
`run_operator_locally` script. It applies the [`acid-minimal-cluster`](../manifests/minimal-postgres-manifest.yaml).
|
||||
`run_operator_locally` script. It applies the [`acid-minimal-cluster`](https://github.com/zalando/postgres-operator/blob/master/manifests/minimal-postgres-manifest.yaml).
|
||||
manifest.
|
||||
|
||||
```bash
|
||||
./run_operator_locally.sh
|
||||
```
|
||||
|
||||
### Helm chart
|
||||
### Manual deployment setup on OpenShift
|
||||
|
||||
Alternatively, the operator can be installed by using the provided [Helm](https://helm.sh/)
|
||||
chart which saves you the manual steps. Clone this repo and change directory to
|
||||
the repo root. With Helm v3 installed you should be able to run:
|
||||
To install the Postgres Operator in OpenShift you have to change the config
|
||||
parameter `kubernetes_use_configmaps` to `"true"`. Otherwise, the operator
|
||||
and Patroni will store leader and config keys in `Endpoints` that are not
|
||||
supported in OpenShift. This requires also a slightly different set of rules
|
||||
for the `postgres-operator` and `postgres-pod` cluster roles.
|
||||
|
||||
```bash
|
||||
helm install postgres-operator ./charts/postgres-operator
|
||||
oc create -f manifests/operator-service-account-rbac-openshift.yaml
|
||||
```
|
||||
|
||||
The chart works with both Helm 2 and Helm 3. The `crd-install` hook from v2 will
|
||||
be skipped with warning when using v3. Documentation for installing applications
|
||||
with Helm 2 can be found in the [v2 docs](https://v2.helm.sh/docs/).
|
||||
### Helm chart
|
||||
|
||||
Alternatively, the operator can be installed by using the provided
|
||||
[Helm](https://helm.sh/) chart which saves you the manual steps. The charts
|
||||
for both the Postgres Operator and its UI are hosted via the `gh-pages` branch.
|
||||
They only work only with Helm v3. Helm v2 support was dropped with v1.8.0.
|
||||
|
||||
```bash
|
||||
# add repo for postgres-operator
|
||||
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
|
||||
|
||||
# install the postgres-operator
|
||||
helm install postgres-operator postgres-operator-charts/postgres-operator
|
||||
|
||||
# add repo for postgres-operator-ui
|
||||
helm repo add postgres-operator-ui-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator-ui
|
||||
|
||||
# install the postgres-operator-ui
|
||||
helm install postgres-operator-ui postgres-operator-ui-charts/postgres-operator-ui
|
||||
```
|
||||
|
||||
## Check if Postgres Operator is running
|
||||
|
||||
|
|
@ -112,8 +131,8 @@ In the following paragraphs we describe how to access and manage PostgreSQL
|
|||
clusters from the command line with kubectl. But it can also be done from the
|
||||
browser-based [Postgres Operator UI](operator-ui.md). Before deploying the UI
|
||||
make sure the operator is running and its REST API is reachable through a
|
||||
[K8s service](../manifests/api-service.yaml). The URL to this API must be
|
||||
configured in the [deployment manifest](../ui/manifests/deployment.yaml#L43)
|
||||
[K8s service](https://github.com/zalando/postgres-operator/blob/master/manifests/api-service.yaml). The URL to this API must be
|
||||
configured in the [deployment manifest](https://github.com/zalando/postgres-operator/blob/master/ui/manifests/deployment.yaml#L43)
|
||||
of the UI.
|
||||
|
||||
To deploy the UI simply apply all its manifests files or use the UI helm chart:
|
||||
|
|
@ -197,7 +216,7 @@ Non-encrypted connections are rejected by default, so set the SSL mode to
|
|||
require:
|
||||
|
||||
```bash
|
||||
export PGPASSWORD=$(kubectl get secret postgres.acid-minimal-cluster.credentials -o 'jsonpath={.data.password}' | base64 -d)
|
||||
export PGPASSWORD=$(kubectl get secret postgres.acid-minimal-cluster.credentials.postgresql.acid.zalan.do -o 'jsonpath={.data.password}' | base64 -d)
|
||||
export PGSSLMODE=require
|
||||
psql -U postgres
|
||||
```
|
||||
|
|
@ -211,7 +230,7 @@ kubectl delete postgresql acid-minimal-cluster
|
|||
```
|
||||
|
||||
This should remove the associated StatefulSet, database Pods, Services and
|
||||
Endpoints. The PersistentVolumes are released and the PodDisruptionBudget is
|
||||
Endpoints. The PersistentVolumes are released and the PodDisruptionBudgets are
|
||||
deleted. Secrets however are not deleted and backups will remain in place.
|
||||
|
||||
When deleting a cluster while it is still starting up or got stuck during that
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ Individual Postgres clusters are described by the Kubernetes *cluster manifest*
|
|||
that has the structure defined by the `postgresql` CRD (custom resource
|
||||
definition). The following section describes the structure of the manifest and
|
||||
the purpose of individual keys. You can take a look at the examples of the
|
||||
[minimal](../../manifests/minimal-postgres-manifest.yaml)
|
||||
[minimal](https://github.com/zalando/postgres-operator/blob/master/manifests/minimal-postgres-manifest.yaml)
|
||||
and the
|
||||
[complete](../../manifests/complete-postgres-manifest.yaml)
|
||||
[complete](https://github.com/zalando/postgres-operator/blob/master/manifests/complete-postgres-manifest.yaml)
|
||||
cluster manifests.
|
||||
|
||||
When Kubernetes resources, such as memory, CPU or volumes, are configured,
|
||||
|
|
@ -53,8 +53,7 @@ Those parameters are grouped under the `metadata` top-level key.
|
|||
These parameters are grouped directly under the `spec` key in the manifest.
|
||||
|
||||
* **teamId**
|
||||
name of the team the cluster belongs to. Changing it after the cluster
|
||||
creation is not supported. Required field.
|
||||
name of the team the cluster belongs to. Required field.
|
||||
|
||||
* **numberOfInstances**
|
||||
total number of instances for a given cluster. The operator parameters
|
||||
|
|
@ -86,30 +85,125 @@ These parameters are grouped directly under the `spec` key in the manifest.
|
|||
requires a custom Spilo image. Note the FSGroup of a Pod cannot be changed
|
||||
without recreating a new Pod. Optional.
|
||||
|
||||
* **livenessProbe**
|
||||
Allows for adding a liveness probe to the Spilo container to detect if it's
|
||||
running properly.
|
||||
|
||||
* **enableMasterLoadBalancer**
|
||||
boolean flag to override the operator defaults (set by the
|
||||
`enable_master_load_balancer` parameter) to define whether to enable the load
|
||||
balancer pointing to the Postgres primary. Optional.
|
||||
|
||||
* **enableMasterPoolerLoadBalancer**
|
||||
boolean flag to override the operator defaults (set by the
|
||||
`enable_master_pooler_load_balancer` parameter) to define whether to enable
|
||||
the load balancer for master pooler pods pointing to the Postgres primary.
|
||||
Optional.
|
||||
|
||||
* **enableReplicaLoadBalancer**
|
||||
boolean flag to override the operator defaults (set by the
|
||||
`enable_replica_load_balancer` parameter) to define whether to enable the
|
||||
load balancer pointing to the Postgres standby instances. Optional.
|
||||
|
||||
* **enableReplicaPoolerLoadBalancer**
|
||||
boolean flag to override the operator defaults (set by the
|
||||
`enable_replica_pooler_load_balancer` parameter) to define whether to enable
|
||||
the load balancer for replica pooler pods pointing to the Postgres standby
|
||||
instances. Optional.
|
||||
|
||||
* **allowedSourceRanges**
|
||||
when one or more load balancers are enabled for the cluster, this parameter
|
||||
defines the comma-separated range of IP networks (in CIDR-notation). The
|
||||
corresponding load balancer is accessible only to the networks defined by
|
||||
this parameter. Optional, when empty the load balancer service becomes
|
||||
inaccessible from outside of the Kubernetes cluster.
|
||||
defines the comma-separated range of IP networks (in CIDR-notation). Both
|
||||
IPv4 (e.g. `192.168.1.0/24`) and IPv6 (e.g. `fd01::/48`) CIDR ranges are
|
||||
supported. The corresponding load balancer is accessible only to the networks
|
||||
defined by this parameter. Optional, when empty the load balancer service
|
||||
becomes inaccessible from outside of the Kubernetes cluster.
|
||||
|
||||
* **enableMasterNodePort**
|
||||
boolean flag to override the operator defaults (set by the
|
||||
`enable_master_node_port` parameter) to define whether to enable the node
|
||||
port pointing to the Postgres primary. Optional. Overrides `enableMasterLoadBalancer`.
|
||||
|
||||
* **enableMasterPoolerNodePort**
|
||||
boolean flag to override the operator defaults (set by the
|
||||
`enable_master_pooler_node_port` parameter) to define whether to enable
|
||||
the node port for master pooler pods pointing to the Postgres primary.
|
||||
Optional. Overrides `enableMasterPoolerLoadBalancer`.
|
||||
|
||||
* **enableReplicaNodePort**
|
||||
boolean flag to override the operator defaults (set by the
|
||||
`enable_replica_node_port` parameter) to define whether to enable the node
|
||||
port pointing to the Postgres standby instances. Optional. Overrides `enableReplicaLoadBalancer`.
|
||||
|
||||
* **enableReplicaPoolerNodePort**
|
||||
boolean flag to override the operator defaults (set by the
|
||||
`enable_replica_pooler_node_port` parameter) to define whether to enable
|
||||
the node port for replica pooler pods pointing to the Postgres standby
|
||||
instances. Optional. Overrides `enableReplicaPoolerLoadBalancer`.
|
||||
|
||||
* **masterNodePort**
|
||||
integer flag to specify a port number for the node port to the Postgres primary.
|
||||
Only used when `enableMasterNodePort` or `enable_master_node_port` are enabled.
|
||||
Optional. Kubernetes will provide a port number for you if not specified.
|
||||
|
||||
* **masterPoolerNodePort**
|
||||
integer flag to specify a port number for the node port for the master pooler pods pointing to the Postgres primary.
|
||||
Only used when `enableMasterPoolerNodePort` or `enable_master_pooler_node_port` are enabled.
|
||||
Optional. Kubernetes will provide a port number for you if not specified.
|
||||
|
||||
* **replicaNodePort**
|
||||
integer flag to specify a port number for the node port pointing to the Postgres standby instances.
|
||||
Only used when `enableReplicaNodePort` or `enable_replica_node_port` are enabled.
|
||||
Optional. Kubernetes will provide a port number for you if not specified.
|
||||
|
||||
* **replicaPoolerNodePort**
|
||||
integer flag to specify a port number for the node port for the replica pooler pods pointing to the Postgres standby instances
|
||||
Only used when `enableReplicaPoolerNodePort` or `enable_replica_pooler_node_port` are enabled.
|
||||
Optional. Kubernetes will provide a port number for you if not specified.
|
||||
|
||||
* **maintenanceWindows**
|
||||
a list which defines specific time frames when certain maintenance operations
|
||||
such as automatic major upgrades or master pod migration are allowed to happen.
|
||||
Accepted formats are "01:00-06:00" for daily maintenance windows or
|
||||
"Sat:00:00-04:00" for specific days, with all times in UTC. Note, when the
|
||||
global config option `enable_maintenance_windows` is false, the specified
|
||||
windows will be ignored.
|
||||
|
||||
* **users**
|
||||
a map of usernames to user flags for the users that should be created in the
|
||||
cluster by the operator. User flags are a list, allowed elements are
|
||||
`SUPERUSER`, `REPLICATION`, `INHERIT`, `LOGIN`, `NOLOGIN`, `CREATEROLE`,
|
||||
`CREATEDB`, `BYPASSURL`. A login user is created by default unless NOLOGIN is
|
||||
`CREATEDB`, `BYPASSRLS`. A login user is created by default unless NOLOGIN is
|
||||
specified, in which case the operator creates a role. One can specify empty
|
||||
flags by providing a JSON empty array '*[]*'. Optional.
|
||||
flags by providing a JSON empty array '*[]*'. If the config option
|
||||
`enable_cross_namespace_secret` is enabled you can specify the namespace in
|
||||
the user name in the form `{namespace}.{username}` and the operator will
|
||||
create the K8s secret in that namespace. The part after the first `.` is
|
||||
considered to be the user name. Optional.
|
||||
|
||||
* **usersWithSecretRotation**
|
||||
list of users to enable credential rotation in K8s secrets. The rotation
|
||||
interval can only be configured globally. On each rotation a new user will
|
||||
be added in the database replacing the `username` value in the secret of
|
||||
the listed user. Although, rotation users inherit all rights from the
|
||||
original role, keep in mind that ownership is not transferred. See more
|
||||
details in the [administrator docs](https://github.com/zalando/postgres-operator/blob/master/docs/administrator.md#password-rotation-in-k8s-secrets).
|
||||
|
||||
* **usersWithInPlaceSecretRotation**
|
||||
list of users to enable in-place password rotation in K8s secrets. The
|
||||
rotation interval can only be configured globally. On each rotation the
|
||||
password value will be replaced in the secrets which the operator reflects
|
||||
in the database, too. List only users here that rarely connect to the
|
||||
database, like a flyway user running a migration on Pod start. See more
|
||||
details in the [administrator docs](https://github.com/zalando/postgres-operator/blob/master/docs/administrator.md#password-replacement-without-extra-users).
|
||||
|
||||
* **usersIgnoringSecretRotation**
|
||||
if you have secret rotation enabled globally you can define a list of
|
||||
of users that should opt out from it, for example if you store credentials
|
||||
outside of K8s, too, and corresponding deployments cannot dynamically
|
||||
reference secrets. Note, you can also opt out from the rotation by removing
|
||||
users from the manifest's `users` section. The operator will not drop them
|
||||
from the database. Optional.
|
||||
|
||||
* **databases**
|
||||
a map of database names to database owners for the databases that should be
|
||||
|
|
@ -142,6 +236,22 @@ These parameters are grouped directly under the `spec` key in the manifest.
|
|||
[administrator docs](https://github.com/zalando/postgres-operator/blob/master/docs/administrator.md#load-balancers-and-allowed-ip-ranges)
|
||||
for more information regarding default values and overwrite rules.
|
||||
|
||||
* **masterServiceAnnotations**
|
||||
A map of key value pairs that gets attached as [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/)
|
||||
to the master service created for the database cluster. Check the
|
||||
[administrator docs](https://github.com/zalando/postgres-operator/blob/master/docs/administrator.md#load-balancers-and-allowed-ip-ranges)
|
||||
for more information regarding default values and overwrite rules.
|
||||
This field overrides `serviceAnnotations` with the same key for the master
|
||||
service if not empty.
|
||||
|
||||
* **replicaServiceAnnotations**
|
||||
A map of key value pairs that gets attached as [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/)
|
||||
to the replica service created for the database cluster. Check the
|
||||
[administrator docs](https://github.com/zalando/postgres-operator/blob/master/docs/administrator.md#load-balancers-and-allowed-ip-ranges)
|
||||
for more information regarding default values and overwrite rules.
|
||||
This field overrides `serviceAnnotations` with the same key for the replica
|
||||
service if not empty.
|
||||
|
||||
* **enableShmVolume**
|
||||
Start a database pod without limitations on shm memory. By default Docker
|
||||
limit `/dev/shm` to `64M` (see e.g. the [docker
|
||||
|
|
@ -168,10 +278,17 @@ These parameters are grouped directly under the `spec` key in the manifest.
|
|||
Determines if the logical backup of this cluster should be taken and uploaded
|
||||
to S3. Default: false. Optional.
|
||||
|
||||
* **logicalBackupRetention**
|
||||
You can set a retention time for the logical backup cron job to remove old backup
|
||||
files after a new backup has been uploaded. Example values are "3 days", "2 weeks", or
|
||||
"1 month". It takes precedence over the global `logical_backup_s3_retention_time`
|
||||
configuration. Currently only supported for AWS. Optional.
|
||||
|
||||
* **logicalBackupSchedule**
|
||||
Schedule for the logical backup K8s cron job. Please take
|
||||
[the reference schedule format](https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#schedule)
|
||||
into account. Optional. Default is: "30 00 \* \* \*"
|
||||
into account. It takes precedence over the global `logical_backup_schedule`
|
||||
configuration. Optional.
|
||||
|
||||
* **additionalVolumes**
|
||||
List of additional volumes to mount in each container of the statefulset pod.
|
||||
|
|
@ -179,12 +296,42 @@ These parameters are grouped directly under the `spec` key in the manifest.
|
|||
[kubernetes volumeSource](https://godoc.org/k8s.io/api/core/v1#VolumeSource).
|
||||
It allows you to mount existing PersistentVolumeClaims, ConfigMaps and Secrets inside the StatefulSet.
|
||||
Also an `emptyDir` volume can be shared between initContainer and statefulSet.
|
||||
Additionaly, you can provide a `SubPath` for volume mount (a file in a configMap source volume, for example).
|
||||
Additionally, you can provide a `SubPath` for volume mount (a file in a configMap source volume, for example).
|
||||
Set `isSubPathExpr` to true if you want to include [API environment variables](https://kubernetes.io/docs/concepts/storage/volumes/#using-subpath-expanded-environment).
|
||||
You can also specify in which container the additional Volumes will be mounted with the `targetContainers` array option.
|
||||
If `targetContainers` is empty, additional volumes will be mounted only in the `postgres` container.
|
||||
If you set the `all` special item, it will be mounted in all containers (postgres + sidecars).
|
||||
Else you can set the list of target containers in which the additional volumes will be mounted (eg : postgres, telegraf)
|
||||
|
||||
## Prepared Databases
|
||||
|
||||
The operator can create databases with default owner, reader and writer roles
|
||||
without the need to specify them under `users` or `databases` sections. Those
|
||||
parameters are grouped under the `preparedDatabases` top-level key. For more
|
||||
information, see [user docs](../user.md#prepared-databases-with-roles-and-default-privileges).
|
||||
|
||||
* **defaultUsers**
|
||||
The operator will always create default `NOLOGIN` roles for defined prepared
|
||||
databases, but if `defaultUsers` is set to `true` three additional `LOGIN`
|
||||
roles with `_user` suffix will get created. Default is `false`.
|
||||
|
||||
* **extensions**
|
||||
map of extensions with target database schema that the operator will install
|
||||
in the database. Optional.
|
||||
|
||||
* **schemas**
|
||||
map of schemas that the operator will create. Optional - if no schema is
|
||||
listed, the operator will create a schema called `data`. Under each schema
|
||||
key, it can be defined if `defaultRoles` (NOLOGIN) and `defaultUsers` (LOGIN)
|
||||
roles shall be created that have schema-exclusive privileges.
|
||||
By default, `defaultRoles` is `true` and `defaultUsers` is false.
|
||||
|
||||
* **secretNamespace**
|
||||
for each default LOGIN role the operator will create a secret. You can
|
||||
specify the namespace in which these secrets will get created, if
|
||||
`enable_cross_namespace_secret` is set to `true` in the config. Otherwise,
|
||||
the cluster namespace is used.
|
||||
|
||||
## Postgres parameters
|
||||
|
||||
Those parameters are grouped under the `postgresql` top-level key, which is
|
||||
|
|
@ -208,7 +355,7 @@ documentation](https://patroni.readthedocs.io/en/latest/SETTINGS.html) for the
|
|||
explanation of `ttl` and `loop_wait` parameters.
|
||||
|
||||
* **initdb**
|
||||
a map of key-value pairs describing initdb parameters. For `data-checksum`,
|
||||
a map of key-value pairs describing initdb parameters. For `data-checksums`,
|
||||
`debug`, `no-locale`, `noclean`, `nosync` and `sync-only` parameters use
|
||||
`true` as the value if you want to set them. Changes to this option do not
|
||||
affect the already initialized clusters. Optional.
|
||||
|
|
@ -254,11 +401,22 @@ explanation of `ttl` and `loop_wait` parameters.
|
|||
* **synchronous_mode_strict**
|
||||
Patroni `synchronous_mode_strict` parameter value. Can be used in addition to `synchronous_mode`. The default is set to `false`. Optional.
|
||||
|
||||
* **synchronous_node_count**
|
||||
Patroni `synchronous_node_count` parameter value. Note, this option is only available for Spilo images with Patroni 2.0+. The default is set to `1`. Optional.
|
||||
|
||||
* **failsafe_mode**
|
||||
Patroni `failsafe_mode` parameter value. If enabled, Patroni will cope
|
||||
with DCS outages by avoiding leader demotion. See the Patroni documentation
|
||||
[here](https://patroni.readthedocs.io/en/master/dcs_failsafe_mode.html) for more details.
|
||||
This feature is included since Patroni 3.0.0. Hence, check the container
|
||||
image in use if this feature is included in the used Patroni version. The
|
||||
default is set to `false`. Optional.
|
||||
|
||||
## Postgres container resources
|
||||
|
||||
Those parameters define [CPU and memory requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/)
|
||||
for the Postgres container. They are grouped under the `resources` top-level
|
||||
key with subgroups `requests` and `limits`.
|
||||
key with subgroups `requests` and `limits`.
|
||||
|
||||
### Requests
|
||||
|
||||
|
|
@ -266,11 +424,19 @@ CPU and memory requests for the Postgres container.
|
|||
|
||||
* **cpu**
|
||||
CPU requests for the Postgres container. Optional, overrides the
|
||||
`default_cpu_requests` operator configuration parameter. Optional.
|
||||
`default_cpu_requests` operator configuration parameter.
|
||||
|
||||
* **memory**
|
||||
memory requests for the Postgres container. Optional, overrides the
|
||||
`default_memory_request` operator configuration parameter. Optional.
|
||||
`default_memory_request` operator configuration parameter.
|
||||
|
||||
* **hugepages-2Mi**
|
||||
hugepages-2Mi requests for the sidecar container.
|
||||
Optional, defaults to not set.
|
||||
|
||||
* **hugepages-1Gi**
|
||||
1Gi hugepages requests for the sidecar container.
|
||||
Optional, defaults to not set.
|
||||
|
||||
### Limits
|
||||
|
||||
|
|
@ -278,11 +444,19 @@ CPU and memory limits for the Postgres container.
|
|||
|
||||
* **cpu**
|
||||
CPU limits for the Postgres container. Optional, overrides the
|
||||
`default_cpu_limits` operator configuration parameter. Optional.
|
||||
`default_cpu_limits` operator configuration parameter.
|
||||
|
||||
* **memory**
|
||||
memory limits for the Postgres container. Optional, overrides the
|
||||
`default_memory_limits` operator configuration parameter. Optional.
|
||||
`default_memory_limits` operator configuration parameter.
|
||||
|
||||
* **hugepages-2Mi**
|
||||
hugepages-2Mi requests for the sidecar container.
|
||||
Optional, defaults to not set.
|
||||
|
||||
* **hugepages-1Gi**
|
||||
1Gi hugepages requests for the sidecar container.
|
||||
Optional, defaults to not set.
|
||||
|
||||
## Parameters defining how to clone the cluster from another one
|
||||
|
||||
|
|
@ -331,12 +505,31 @@ under the `clone` top-level key and do not affect the already running cluster.
|
|||
## Standby cluster
|
||||
|
||||
On startup, an existing `standby` top-level key creates a standby Postgres
|
||||
cluster streaming from a remote location. So far only streaming from a S3 WAL
|
||||
archive is supported.
|
||||
cluster streaming from a remote location - either from a S3 or GCS WAL
|
||||
archive, a remote primary, or a combination of both. At least one of
|
||||
`s3_wal_path`, `gs_wal_path`, or `standby_host` must be specified.
|
||||
Note that `s3_wal_path` and `gs_wal_path` are mutually exclusive.
|
||||
|
||||
* **s3_wal_path**
|
||||
the url to S3 bucket containing the WAL archive of the remote primary.
|
||||
Required when the `standby` section is present.
|
||||
Can be combined with `standby_host` for additional redundancy.
|
||||
|
||||
* **gs_wal_path**
|
||||
the url to GS bucket containing the WAL archive of the remote primary.
|
||||
Can be combined with `standby_host` for additional redundancy.
|
||||
|
||||
* **standby_host**
|
||||
hostname or IP address of the primary to stream from.
|
||||
Can be specified alone or combined with either `s3_wal_path` or `gs_wal_path`.
|
||||
|
||||
* **standby_port**
|
||||
TCP port on which the primary is listening for connections. Patroni will
|
||||
use `"5432"` if not set.
|
||||
|
||||
* **standby_primary_slot_name**
|
||||
name of the replication slot to use on the primary server when streaming
|
||||
from a remote primary. See the Patroni documentation
|
||||
[here](https://patroni.readthedocs.io/en/latest/standby_cluster.html) for more details. Optional.
|
||||
|
||||
## Volume properties
|
||||
|
||||
|
|
@ -356,6 +549,9 @@ properties of the persistent storage that stores Postgres data.
|
|||
* **subPath**
|
||||
Subpath to use when mounting volume into Spilo container. Optional.
|
||||
|
||||
* **isSubPathExpr**
|
||||
Set it to true if the specified subPath is an expression. 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.
|
||||
|
|
@ -364,6 +560,11 @@ properties of the persistent storage that stores Postgres data.
|
|||
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.
|
||||
|
||||
* **selector**
|
||||
A label query over PVs to consider for binding. See the [Kubernetes
|
||||
documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/)
|
||||
for details on using `matchLabels` and `matchExpressions`. Optional
|
||||
|
||||
## Sidecar definitions
|
||||
|
||||
Those parameters are defined under the `sidecars` key. They consist of a list
|
||||
|
|
@ -398,6 +599,14 @@ CPU and memory requests for the sidecar container.
|
|||
memory requests for the sidecar container. Optional, overrides the
|
||||
`default_memory_request` operator configuration parameter. Optional.
|
||||
|
||||
* **hugepages-2Mi**
|
||||
hugepages-2Mi requests for the sidecar container.
|
||||
Optional, defaults to not set.
|
||||
|
||||
* **hugepages-1Gi**
|
||||
1Gi hugepages requests for the sidecar container.
|
||||
Optional, defaults to not set.
|
||||
|
||||
### Limits
|
||||
|
||||
CPU and memory limits for the sidecar container.
|
||||
|
|
@ -410,6 +619,14 @@ CPU and memory limits for the sidecar container.
|
|||
memory limits for the sidecar container. Optional, overrides the
|
||||
`default_memory_limits` operator configuration parameter. Optional.
|
||||
|
||||
* **hugepages-2Mi**
|
||||
hugepages-2Mi requests for the sidecar container.
|
||||
Optional, defaults to not set.
|
||||
|
||||
* **hugepages-1Gi**
|
||||
1Gi hugepages requests for the sidecar container.
|
||||
Optional, defaults to not set.
|
||||
|
||||
## Connection pooler
|
||||
|
||||
Parameters are grouped under the `connectionPooler` top-level key and specify
|
||||
|
|
@ -444,7 +661,9 @@ for both master and replica pooler services (if `enableReplicaConnectionPooler`
|
|||
|
||||
## Custom TLS certificates
|
||||
|
||||
Those parameters are grouped under the `tls` top-level key.
|
||||
Those parameters are grouped under the `tls` top-level key. Note, you have to
|
||||
define `spiloFSGroup` in the Postgres cluster manifest or `spilo_fsgroup` in
|
||||
the global configuration before adding the `tls` section'.
|
||||
|
||||
* **secretName**
|
||||
By setting the `secretName` value, the cluster will switch to load the given
|
||||
|
|
@ -473,3 +692,70 @@ Those parameters are grouped under the `tls` top-level key.
|
|||
relative to the "/tls/", which is mount path of the tls secret.
|
||||
If `caSecretName` is defined, the ca.crt path is relative to "/tlsca/",
|
||||
otherwise to the same "/tls/".
|
||||
|
||||
## Change data capture streams
|
||||
|
||||
This sections enables change data capture (CDC) streams via Postgres'
|
||||
[logical decoding](https://www.postgresql.org/docs/18/logicaldecoding.html)
|
||||
feature and `pgoutput` plugin. While the Postgres operator takes responsibility
|
||||
for providing the setup to publish change events, it relies on external tools
|
||||
to consume them. At Zalando, we are using a workflow based on
|
||||
[Debezium Connector](https://debezium.io/documentation/reference/stable/connectors/postgresql.html)
|
||||
which can feed streams into Zalando’s distributed event broker [Nakadi](https://nakadi.io/)
|
||||
among others.
|
||||
|
||||
The Postgres Operator creates custom resources for Zalando's internal CDC
|
||||
operator which will be used to set up the consumer part. Each stream object
|
||||
can have the following properties:
|
||||
|
||||
* **applicationId**
|
||||
The application name to which the database and CDC belongs to. For each
|
||||
set of streams with a distinct `applicationId` a separate stream resource as
|
||||
well as a separate logical replication slot will be created. This means there
|
||||
can be different streams in the same database and streams with the same
|
||||
`applicationId` are bundled in one stream resource. The stream resource will
|
||||
be called like the Postgres cluster plus "-<applicationId>" suffix. Required.
|
||||
|
||||
* **database**
|
||||
Name of the database from where events will be published via Postgres'
|
||||
logical decoding feature. The operator will take care of updating the
|
||||
database configuration (setting `wal_level: logical`, creating logical
|
||||
replication slots, using output plugin `pgoutput` and creating a dedicated
|
||||
replication user). Required.
|
||||
|
||||
* **tables**
|
||||
Defines a map of table names and their properties (`eventType`, `idColumn`
|
||||
and `payloadColumn`). Required.
|
||||
The CDC operator is following the [outbox pattern](https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/).
|
||||
The application is responsible for putting events into a (JSON/B or VARCHAR)
|
||||
payload column of the outbox table in the structure of the specified target
|
||||
event type. The operator will create a [PUBLICATION](https://www.postgresql.org/docs/18/logical-replication-publication.html)
|
||||
in Postgres for all tables specified for one `database` and `applicationId`.
|
||||
The CDC operator will consume from it shortly after transactions are
|
||||
committed to the outbox table. The `idColumn` will be used in telemetry for
|
||||
the CDC operator. The names for `idColumn` and `payloadColumn` can be
|
||||
configured. Defaults are `id` and `payload`. The target `eventType` has to
|
||||
be defined. One can also specify a `recoveryEventType` that will be used
|
||||
for a dead letter queue. By enabling `ignoreRecovery`, you can choose to
|
||||
ignore failing events.
|
||||
|
||||
* **filter**
|
||||
Streamed events can be filtered by a jsonpath expression for each table.
|
||||
Optional.
|
||||
|
||||
* **enableRecovery**
|
||||
Flag to enable a dead letter queue recovery for all streams tables.
|
||||
Alternatively, recovery can also be enable for single outbox tables by only
|
||||
specifying a `recoveryEventType` and no `enableRecovery` flag. When set to
|
||||
false or missing, events will be retried until consuming succeeded. You can
|
||||
use a `filter` expression to get rid of poison pills. Optional.
|
||||
|
||||
* **batchSize**
|
||||
Defines the size of batches in which events are consumed. Optional.
|
||||
Defaults to 1.
|
||||
|
||||
* **cpu**
|
||||
CPU requests to be set as an annotation on the stream resource. Optional.
|
||||
|
||||
* **memory**
|
||||
memory requests to be set as an annotation on the stream resource. Optional.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@ The following command-line options are supported for the operator:
|
|||
off can can be overridden by the aforementioned operator configuration
|
||||
option.
|
||||
|
||||
* **-kubeqps**
|
||||
set the maximum number of Kubernetes API requests per second. Default is 10.
|
||||
|
||||
* **-kubeburst**
|
||||
set the burst limit for Kubernetes API requests, allowing temporary spikes beyond the configured QPS. Default is 20.
|
||||
|
||||
In addition to that, standard [glog
|
||||
flags](https://godoc.org/github.com/golang/glog) are also supported. For
|
||||
instance, one may want to add `-alsologtostderr` and `-v=8` to debug the
|
||||
|
|
|
|||
|
|
@ -3,32 +3,46 @@
|
|||
There are two mutually-exclusive methods to set the Postgres Operator
|
||||
configuration.
|
||||
|
||||
* ConfigMaps-based, the legacy one. The configuration is supplied in a
|
||||
key-value configmap, defined by the `CONFIG_MAP_NAME` environment variable.
|
||||
Non-scalar values, i.e. lists or maps, are encoded in the value strings using
|
||||
the comma-based syntax for lists and coma-separated `key:value` syntax for
|
||||
maps. String values containing ':' should be enclosed in quotes. The
|
||||
configuration is flat, parameter group names below are not reflected in the
|
||||
configuration structure. There is an
|
||||
[example](../../manifests/configmap.yaml)
|
||||
* ConfigMaps-based, the legacy one
|
||||
* CRD-based configuration
|
||||
|
||||
* CRD-based configuration. The configuration is stored in a custom YAML
|
||||
manifest. The manifest is an instance of the custom resource definition (CRD)
|
||||
called `OperatorConfiguration`. The operator registers this CRD during the
|
||||
start and uses it for configuration if the [operator deployment manifest](../../manifests/postgres-operator.yaml#L36)
|
||||
sets the `POSTGRES_OPERATOR_CONFIGURATION_OBJECT` env variable to a non-empty
|
||||
value. The variable should point to the `postgresql-operator-configuration`
|
||||
object in the operator's namespace.
|
||||
Variable names are underscore-separated words.
|
||||
|
||||
The CRD-based configuration is a regular YAML document; non-scalar keys are
|
||||
simply represented in the usual YAML way. There are no default values built-in
|
||||
in the operator, each parameter that is not supplied in the configuration
|
||||
receives an empty value. In order to create your own configuration just copy
|
||||
the [default one](../../manifests/postgresql-operator-default-configuration.yaml)
|
||||
and change it.
|
||||
### ConfigMaps-based
|
||||
The configuration is supplied in a
|
||||
key-value configmap, defined by the `CONFIG_MAP_NAME` environment variable.
|
||||
Non-scalar values, i.e. lists or maps, are encoded in the value strings using
|
||||
the comma-based syntax for lists and coma-separated `key:value` syntax for
|
||||
maps. String values containing ':' should be enclosed in quotes. The
|
||||
configuration is flat, parameter group names below are not reflected in the
|
||||
configuration structure. There is an
|
||||
[example](https://github.com/zalando/postgres-operator/blob/master/manifests/configmap.yaml)
|
||||
|
||||
To test the CRD-based configuration locally, use the following
|
||||
```bash
|
||||
For the configmap configuration, the [default parameter values](https://github.com/zalando/postgres-operator/blob/master/pkg/util/config/config.go#L14)
|
||||
mentioned here are likely to be overwritten in your local operator installation
|
||||
via your local version of the operator configmap. In the case you use the
|
||||
operator CRD, all the CRD defaults are provided in the
|
||||
[operator's default configuration manifest](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresql-operator-default-configuration.yaml)
|
||||
|
||||
### CRD-based configuration
|
||||
The configuration is stored in a custom YAML
|
||||
manifest. The manifest is an instance of the custom resource definition (CRD)
|
||||
called `OperatorConfiguration`. The operator registers this CRD during the
|
||||
start and uses it for configuration if the [operator deployment manifest](https://github.com/zalando/postgres-operator/blob/master/manifests/postgres-operator.yaml#L36)
|
||||
sets the `POSTGRES_OPERATOR_CONFIGURATION_OBJECT` env variable to a non-empty
|
||||
value. The variable should point to the `postgresql-operator-configuration`
|
||||
object in the operator's namespace.
|
||||
|
||||
The CRD-based configuration is a regular YAML document; non-scalar keys are
|
||||
simply represented in the usual YAML way. There are no default values built-in
|
||||
in the operator, each parameter that is not supplied in the configuration
|
||||
receives an empty value. In order to create your own configuration just copy
|
||||
the [default one](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresql-operator-default-configuration.yaml)
|
||||
and change it.
|
||||
|
||||
To test the CRD-based configuration locally, use the following
|
||||
|
||||
```bash
|
||||
kubectl create -f manifests/operatorconfiguration.crd.yaml # registers the CRD
|
||||
kubectl create -f manifests/postgresql-operator-default-configuration.yaml
|
||||
|
||||
|
|
@ -36,7 +50,7 @@ configuration.
|
|||
kubectl create -f manifests/postgres-operator.yaml # set the env var as mentioned above
|
||||
|
||||
kubectl get operatorconfigurations postgresql-operator-default-configuration -o yaml
|
||||
```
|
||||
```
|
||||
|
||||
The CRD-based configuration is more powerful than the one based on ConfigMaps
|
||||
and should be used unless there is a compatibility requirement to use an already
|
||||
|
|
@ -57,24 +71,17 @@ parameters, those parameters have no effect and are replaced by the
|
|||
`CRD_READY_WAIT_INTERVAL` and `CRD_READY_WAIT_TIMEOUT` environment variables.
|
||||
They will be deprecated and removed in the future.
|
||||
|
||||
For the configmap configuration, the [default parameter values](../../pkg/util/config/config.go#L14)
|
||||
mentioned here are likely to be overwritten in your local operator installation
|
||||
via your local version of the operator configmap. In the case you use the
|
||||
operator CRD, all the CRD defaults are provided in the
|
||||
[operator's default configuration manifest](../../manifests/postgresql-operator-default-configuration.yaml)
|
||||
|
||||
Variable names are underscore-separated words.
|
||||
|
||||
|
||||
## General
|
||||
|
||||
Those are top-level keys, containing both leaf keys and groups.
|
||||
|
||||
* **enable_crd_validation**
|
||||
toggles if the operator will create or update CRDs with
|
||||
[OpenAPI v3 schema validation](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#validation)
|
||||
* **enable_crd_registration**
|
||||
Instruct the operator to create/update the CRDs. If disabled the operator will rely on the CRDs being managed separately.
|
||||
The default is `true`.
|
||||
|
||||
* **crd_categories**
|
||||
The operator will register CRDs in the `all` category by default so that they will be returned by a `kubectl get all` call. You are free to change categories or leave them empty.
|
||||
|
||||
* **enable_lazy_spilo_upgrade**
|
||||
Instruct operator to update only the statefulsets with new images (Spilo and InitContainers) without immediately doing the rolling update. The assumption is pods will be re-started later with new images, for example due to the node rotation.
|
||||
The default is `false`.
|
||||
|
|
@ -82,8 +89,10 @@ Those are top-level keys, containing both leaf keys and groups.
|
|||
* **enable_pgversion_env_var**
|
||||
With newer versions of Spilo, it is preferable to use `PGVERSION` pod environment variable instead of the setting `postgresql.bin_dir` in the `SPILO_CONFIGURATION` env variable. When this option is true, the operator sets `PGVERSION` and omits `postgresql.bin_dir` from `SPILO_CONFIGURATION`. When false, the `postgresql.bin_dir` is set. This setting takes precedence over `PGVERSION`; see PR 222 in Spilo. The default is `true`.
|
||||
|
||||
* **enable_spilo_wal_path_compat**
|
||||
enables backwards compatible path between Spilo 12 and Spilo 13 images. The default is `false`.
|
||||
* **enable_team_id_clustername_prefix**
|
||||
To lower the risk of name clashes between clusters of different teams you
|
||||
can turn on this flag and the operator will sync only clusters where the
|
||||
name starts with the `teamId` (from `spec`) plus `-`. Default is `false`.
|
||||
|
||||
* **etcd_host**
|
||||
Etcd connection string for Patroni defined as `host:port`. Not required when
|
||||
|
|
@ -93,8 +102,13 @@ Those are top-level keys, containing both leaf keys and groups.
|
|||
* **kubernetes_use_configmaps**
|
||||
Select if setup uses endpoints (default), or configmaps to manage leader when
|
||||
DCS is kubernetes (not etcd or similar). In OpenShift it is not possible to
|
||||
use endpoints option, and configmaps is required. By default,
|
||||
`kubernetes_use_configmaps: false`, meaning endpoints will be used.
|
||||
use endpoints option, and configmaps is required. Starting with K8s 1.33,
|
||||
endpoints are marked as deprecated. It's recommended to switch to config maps
|
||||
instead. But, to do so make sure you scale the Postgres cluster down to just
|
||||
one primary pod (e.g. using `max_instances` option). Otherwise, you risk
|
||||
running into a split-brain scenario.
|
||||
By default, `kubernetes_use_configmaps: false`, meaning endpoints will be used.
|
||||
Starting from v1.16.0 the default will be changed to `true`.
|
||||
|
||||
* **docker_image**
|
||||
Spilo Docker image for Postgres instances. For production, don't rely on the
|
||||
|
|
@ -140,6 +154,31 @@ Those are top-level keys, containing both leaf keys and groups.
|
|||
When `-1` is specified for `min_instances`, no limits are applied. The default
|
||||
is `-1`.
|
||||
|
||||
* **ignore_instance_limits_annotation_key**
|
||||
for some clusters it might be required to scale beyond the limits that can be
|
||||
configured with `min_instances` and `max_instances` options. You can define
|
||||
an annotation key that can be used as a toggle in cluster manifests to ignore
|
||||
globally configured instance limits. The value must be `"true"` to be
|
||||
effective. The default is empty which means the feature is disabled.
|
||||
|
||||
* **ignore_resources_limits_annotation_key**
|
||||
for some clusters it might be required to request resources beyond the globally
|
||||
configured thresholds for maximum requests and minimum limits. You can define
|
||||
an annotation key that can be used as a toggle in cluster manifests to ignore
|
||||
the thresholds. The value must be `"true"` to be effective. The default is empty
|
||||
which means the feature is disabled.
|
||||
|
||||
* **enable_maintenance_windows**
|
||||
toggle for using the maintenance windows feature. Default is `"true"`.
|
||||
|
||||
* **maintenance_windows**
|
||||
a list which defines specific time frames when certain maintenance
|
||||
operations such as automatic major upgrades or master pod migration are
|
||||
allowed to happen for all database clusters. Accepted formats are
|
||||
"01:00-06:00" for daily maintenance windows or "Sat:00:00-04:00" for
|
||||
specific days, with all times in UTC. Locally defined maintenance
|
||||
windows take precedence over globally configured ones.
|
||||
|
||||
* **resync_period**
|
||||
period between consecutive sync requests. The default is `30m`.
|
||||
|
||||
|
|
@ -148,13 +187,14 @@ Those are top-level keys, containing both leaf keys and groups.
|
|||
|
||||
* **set_memory_request_to_limit**
|
||||
Set `memory_request` to `memory_limit` for all Postgres clusters (the default
|
||||
value is also increased). This prevents certain cases of memory overcommitment
|
||||
at the cost of overprovisioning memory and potential scheduling problems for
|
||||
containers with high memory limits due to the lack of memory on Kubernetes
|
||||
cluster nodes. This affects all containers created by the operator (Postgres,
|
||||
Scalyr sidecar, and other sidecars except **sidecars** defined in the operator
|
||||
configuration); to set resources for the operator's own container, change the
|
||||
[operator deployment manually](../../manifests/postgres-operator.yaml#L20).
|
||||
value is also increased but configured `max_memory_request` can not be
|
||||
bypassed). This prevents certain cases of memory overcommitment at the cost
|
||||
of overprovisioning memory and potential scheduling problems for containers
|
||||
with high memory limits due to the lack of memory on Kubernetes cluster
|
||||
nodes. This affects all containers created by the operator (Postgres,
|
||||
connection pooler, logical backup, scalyr sidecar, and other sidecars except
|
||||
**sidecars** defined in the operator configuration); to set resources for the
|
||||
operator's own container, change the [operator deployment manually](https://github.com/zalando/postgres-operator/blob/master/manifests/postgres-operator.yaml#L20).
|
||||
The default is `false`.
|
||||
|
||||
## Postgres users
|
||||
|
|
@ -170,28 +210,68 @@ under the `users` key.
|
|||
Postgres username used for replication between instances. The default is
|
||||
`standby`.
|
||||
|
||||
* **additional_owner_roles**
|
||||
Specifies database roles that will be granted to all database owners. Owners
|
||||
can then use `SET ROLE` to obtain privileges of these roles to e.g. create
|
||||
or update functionality from extensions as part of a migration script. One
|
||||
such role can be `cron_admin` which is provided by the Spilo docker image to
|
||||
set up cron jobs inside the `postgres` database. In general, roles listed
|
||||
here should be preconfigured in the docker image and already exist in the
|
||||
database cluster on startup. Otherwise, syncing roles will return an error
|
||||
on each cluster sync process. Alternatively, you have to create the role and
|
||||
do the GRANT manually. Note, the operator will not allow additional owner
|
||||
roles to be members of database owners because it should be vice versa. If
|
||||
the operator cannot set up the correct membership it tries to revoke all
|
||||
additional owner roles from database owners. Default is `empty`.
|
||||
|
||||
* **enable_password_rotation**
|
||||
For all `LOGIN` roles that are not database owners the operator can rotate
|
||||
credentials in the corresponding K8s secrets by replacing the username and
|
||||
password. This means, new users will be added on each rotation inheriting
|
||||
all privileges from the original roles. The rotation date (in YYMMDD format)
|
||||
is appended to the names of the new user. The timestamp of the next rotation
|
||||
is written to the secret. The default is `false`.
|
||||
|
||||
* **password_rotation_interval**
|
||||
If password rotation is enabled (either from config or cluster manifest) the
|
||||
interval can be configured with this parameter. The measure is in days which
|
||||
means daily rotation (`1`) is the most frequent interval possible.
|
||||
Default is `90`.
|
||||
|
||||
* **password_rotation_user_retention**
|
||||
To avoid an ever growing amount of new users due to password rotation the
|
||||
operator will remove the created users again after a certain amount of days
|
||||
has passed. The number can be configured with this parameter. However, the
|
||||
operator will check that the retention policy is at least twice as long as
|
||||
the rotation interval and update to this minimum in case it is not.
|
||||
Default is `180`.
|
||||
|
||||
## Major version upgrades
|
||||
|
||||
Parameters configuring automatic major version upgrades. In a
|
||||
Parameters configuring automatic major version upgrades. In a
|
||||
CRD-configuration, they are grouped under the `major_version_upgrade` key.
|
||||
|
||||
* **major_version_upgrade_mode**
|
||||
Postgres Operator supports [in-place major version upgrade](../administrator.md#in-place-major-version-upgrade)
|
||||
Postgres Operator supports [in-place major version upgrade](../administrator.md#in-place-major-version-upgrade)
|
||||
with three different modes:
|
||||
`"off"` = no upgrade by the operator,
|
||||
`"manual"` = manifest triggers action,
|
||||
`"full"` = manifest and minimal version violation trigger upgrade.
|
||||
Note, that with all three modes increasing the version in the manifest will
|
||||
trigger a rolling update of the pods. The default is `"off"`.
|
||||
trigger a rolling update of the pods. The default is `"manual"`.
|
||||
|
||||
* **major_version_upgrade_team_allow_list**
|
||||
Upgrades will only be carried out for clusters of listed teams when mode is
|
||||
set to "off". The default is empty.
|
||||
|
||||
* **minimal_major_version**
|
||||
The minimal Postgres major version that will not automatically be upgraded
|
||||
when `major_version_upgrade_mode` is set to `"full"`. The default is `"9.5"`.
|
||||
when `major_version_upgrade_mode` is set to `"full"`. The default is `"14"`.
|
||||
|
||||
* **target_major_version**
|
||||
The target Postgres major version when upgrading clusters automatically
|
||||
which violate the configured allowed `minimal_major_version` when
|
||||
`major_version_upgrade_mode` is set to `"full"`. The default is `"13"`.
|
||||
`major_version_upgrade_mode` is set to `"full"`. The default is `"18"`.
|
||||
|
||||
## Kubernetes resources
|
||||
|
||||
|
|
@ -199,6 +279,31 @@ Parameters to configure cluster-related Kubernetes objects created by the
|
|||
operator, as well as some timeouts associated with them. In a CRD-based
|
||||
configuration they are grouped under the `kubernetes` key.
|
||||
|
||||
* **enable_finalizers**
|
||||
By default, a deletion of the Postgresql resource will trigger an event
|
||||
that leads to a cleanup of all child resources. However, if the database
|
||||
cluster is in a broken state (e.g. failed initialization) and the operator
|
||||
cannot fully sync it, there can be leftovers. By enabling finalizers the
|
||||
operator will ensure all managed resources are deleted prior to the
|
||||
Postgresql resource. See also [admin docs](../administrator.md#owner-references-and-finalizers)
|
||||
for more information The default is `false`.
|
||||
|
||||
* **enable_owner_references**
|
||||
The operator can set owner references on its child resources (except PVCs,
|
||||
Patroni config service/endpoint, cross-namespace secrets) to improve cluster
|
||||
monitoring and enable cascading deletion. The default is `false`. Warning,
|
||||
enabling this option disables configured delete protection checks (see below).
|
||||
|
||||
* **delete_annotation_date_key**
|
||||
key name for annotation that compares manifest value with current date in the
|
||||
YYYY-MM-DD format. Allowed pattern: `'([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'`.
|
||||
The default is empty which also disables this delete protection check.
|
||||
|
||||
* **delete_annotation_name_key**
|
||||
key name for annotation that compares manifest value with Postgres cluster name.
|
||||
Allowed pattern: `'([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'`. The default is
|
||||
empty which also disables this delete protection check.
|
||||
|
||||
* **pod_service_account_name**
|
||||
service account used by Patroni running on individual Pods to communicate
|
||||
with the operator. Required even if native Kubernetes support in Patroni is
|
||||
|
|
@ -217,33 +322,33 @@ configuration they are grouped under the `kubernetes` key.
|
|||
sufficient for the pods to start and for Patroni to access K8s endpoints;
|
||||
service account on its own lacks any such rights starting with K8s v1.8. If
|
||||
not explicitly defined by the user, a simple definition that binds the
|
||||
account to the 'postgres-pod' [cluster role](../../manifests/operator-service-account-rbac.yaml#L198)
|
||||
account to the 'postgres-pod' [cluster role](https://github.com/zalando/postgres-operator/blob/master/manifests/operator-service-account-rbac.yaml#L198)
|
||||
will be used. The default is empty.
|
||||
|
||||
* **pod_terminate_grace_period**
|
||||
Postgres pods are [terminated forcefully](https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods)
|
||||
Postgres pods are [terminated forcefully](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination)
|
||||
after this timeout. The default is `5m`.
|
||||
|
||||
* **liveness_probe**
|
||||
Allows for adding a liveness probe to the Spilo container to detect if it's
|
||||
running properly. Cannot be configured via ConfigMap. Default is empty.
|
||||
|
||||
* **custom_pod_annotations**
|
||||
This key/value map provides a list of annotations that get attached to each pod
|
||||
of a database created by the operator. If the annotation key is also provided
|
||||
by the database definition, the database definition value is used.
|
||||
|
||||
* **delete_annotation_date_key**
|
||||
key name for annotation that compares manifest value with current date in the
|
||||
YYYY-MM-DD format. Allowed pattern: `'([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'`.
|
||||
The default is empty which also disables this delete protection check.
|
||||
|
||||
* **delete_annotation_name_key**
|
||||
key name for annotation that compares manifest value with Postgres cluster name.
|
||||
Allowed pattern: `'([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'`. The default is
|
||||
empty which also disables this delete protection check.
|
||||
|
||||
* **downscaler_annotations**
|
||||
An array of annotations that should be passed from Postgres CRD on to the
|
||||
statefulset and, if exists, to the connection pooler deployment as well.
|
||||
Regular expressions like `downscaler/*` etc. are also accepted. Can be used
|
||||
with [kube-downscaler](https://github.com/hjacobs/kube-downscaler).
|
||||
with [kube-downscaler](https://codeberg.org/hjacobs/kube-downscaler).
|
||||
|
||||
* **ignored_annotations**
|
||||
Some K8s tools inject and update annotations out of the Postgres Operator
|
||||
control. This can cause rolling updates on each cluster sync cycle. With
|
||||
this option you can specify an array of annotation keys that should be
|
||||
ignored when comparing K8s resources on sync. The default is empty.
|
||||
|
||||
* **watched_namespace**
|
||||
The operator watches for Postgres objects in the given namespace. If not
|
||||
|
|
@ -252,11 +357,40 @@ configuration they are grouped under the `kubernetes` key.
|
|||
pod namespace).
|
||||
|
||||
* **pdb_name_format**
|
||||
defines the template for PDB (Pod Disruption Budget) names created by the
|
||||
defines the template for primary PDB (Pod Disruption Budget) name created by the
|
||||
operator. The default is `postgres-{cluster}-pdb`, where `{cluster}` is
|
||||
replaced by the cluster name. Only the `{cluster}` placeholders is allowed in
|
||||
the template.
|
||||
|
||||
* **pdb_master_label_selector**
|
||||
By default the primary PDB will match the master role hence preventing nodes to be
|
||||
drained if the node_readiness_label is not used. If this option if set to
|
||||
`false` the `spilo-role=master` selector will not be added to the PDB.
|
||||
|
||||
* **persistent_volume_claim_retention_policy**
|
||||
The operator tries to protect volumes as much as possible. If somebody
|
||||
accidentally deletes the statefulset or scales in the `numberOfInstances` the
|
||||
Persistent Volume Claims and thus Persistent Volumes will be retained.
|
||||
However, this can have some consequences when you scale out again at a much
|
||||
later point, for example after the cluster's Postgres major version has been
|
||||
upgraded, because the old volume runs the old Postgres version with stale data.
|
||||
Even if the version has not changed the replication lag could be massive. In
|
||||
this case a reinitialization of the re-added member would make sense. You can
|
||||
also modify the [retention policy of PVCs](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#persistentvolumeclaim-retention) in the operator configuration.
|
||||
The behavior can be changed for two scenarios: `when_deleted` - default is
|
||||
`"retain"` - or `when_scaled` - default is also `"retain"`. The other possible
|
||||
option is `delete`.
|
||||
|
||||
* **enable_secrets_deletion**
|
||||
By default, the operator deletes secrets when removing the Postgres cluster
|
||||
manifest. To keep secrets, set this option to `false`. The default is `true`.
|
||||
|
||||
* **enable_persistent_volume_claim_deletion**
|
||||
By default, the operator deletes persistent volume claims when removing the
|
||||
Postgres cluster manifest, no matter if `persistent_volume_claim_retention_policy`
|
||||
on the statefulset is set to `retain`. To keep PVCs set this option to `false`.
|
||||
The default is `true`.
|
||||
|
||||
* **enable_pod_disruption_budget**
|
||||
PDB is enabled by default to protect the cluster from voluntarily disruptions
|
||||
and hence unwanted DB downtime. However, on some cloud providers it could be
|
||||
|
|
@ -264,6 +398,11 @@ configuration they are grouped under the `kubernetes` key.
|
|||
[admin docs](../administrator.md#pod-disruption-budget) for more information.
|
||||
Default is true.
|
||||
|
||||
* **enable_cross_namespace_secret**
|
||||
To allow secrets in a different namespace other than the Postgres cluster
|
||||
namespace. Once enabled, specify the namespace in the user name under the
|
||||
`users` section in the form `{namespace}.{username}`. The default is `false`.
|
||||
|
||||
* **enable_init_containers**
|
||||
global option to allow for creating init containers in the cluster manifest to
|
||||
run actions before Spilo is started. Default is true.
|
||||
|
|
@ -273,13 +412,21 @@ configuration they are grouped under the `kubernetes` key.
|
|||
to run alongside Spilo on the same pod. Globally defined sidecars are always
|
||||
enabled. Default is true.
|
||||
|
||||
* **share_pgsocket_with_sidecars**
|
||||
global option to create an emptyDir volume named `postgresql-run`. This is
|
||||
mounted by all containers at `/var/run/postgresql` sharing the unix socket of
|
||||
PostgreSQL (`pg_socket`) with the sidecars this way.
|
||||
Default is `false`.
|
||||
|
||||
* **secret_name_template**
|
||||
a template for the name of the database user secrets generated by the
|
||||
operator. `{username}` is replaced with name of the secret, `{cluster}` with
|
||||
the name of the cluster, `{tprkind}` with the kind of CRD (formerly known as
|
||||
TPR) and `{tprgroup}` with the group of the CRD. No other placeholders are
|
||||
allowed. The default is
|
||||
`{username}.{cluster}.credentials.{tprkind}.{tprgroup}`.
|
||||
operator. `{namespace}` is replaced with name of the namespace if
|
||||
`enable_cross_namespace_secret` is set, otherwise the
|
||||
secret is in cluster's namespace. `{username}` is replaced with name of the
|
||||
secret, `{cluster}` with the name of the cluster, `{tprkind}` with the kind
|
||||
of CRD (formerly known as TPR) and `{tprgroup}` with the group of the CRD.
|
||||
No other placeholders are allowed. The default is
|
||||
`{namespace}.{username}.{cluster}.credentials.{tprkind}.{tprgroup}`.
|
||||
|
||||
* **cluster_domain**
|
||||
defines the default DNS domain for the kubernetes cluster the operator is
|
||||
|
|
@ -329,11 +476,16 @@ configuration they are grouped under the `kubernetes` key.
|
|||
|
||||
* **node_readiness_label**
|
||||
a set of labels that a running and active node should possess to be
|
||||
considered `ready`. The operator uses values of those labels to detect the
|
||||
start of the Kubernetes cluster upgrade procedure and move master pods off
|
||||
the nodes to be decommissioned. When the set is not empty, the operator also
|
||||
assigns the `Affinity` clause to the Postgres pods to be scheduled only on
|
||||
`ready` nodes. The default is empty.
|
||||
considered `ready`. When the set is not empty, the operator assigns the
|
||||
`nodeAffinity` clause to the Postgres pods to be scheduled only on `ready`
|
||||
nodes. The default is empty.
|
||||
|
||||
* **node_readiness_label_merge**
|
||||
If a `nodeAffinity` is also specified in the postgres cluster manifest
|
||||
it will get merged with the `node_readiness_label` affinity on the pods.
|
||||
The merge strategy can be configured - it can either be "AND" or "OR".
|
||||
See [user docs](../user.md#use-taints-tolerations-and-node-affinity-for-dedicated-postgresql-nodes)
|
||||
for more details. Default is "OR".
|
||||
|
||||
* **toleration**
|
||||
a dictionary that should contain `key`, `operator`, `value` and
|
||||
|
|
@ -343,10 +495,16 @@ configuration they are grouped under the `kubernetes` key.
|
|||
|
||||
* **pod_environment_configmap**
|
||||
namespaced name of the ConfigMap with environment variables to populate on
|
||||
every pod. Right now this ConfigMap is searched in the namespace of the
|
||||
Postgres cluster. All variables from that ConfigMap are injected to the pod's
|
||||
environment, on conflicts they are overridden by the environment variables
|
||||
generated by the operator. The default is empty.
|
||||
every pod. All variables from that ConfigMap are injected to the pod's
|
||||
environment if they not if conflict with the environment variables generated
|
||||
by the operator. The WAL location (bucket path) can be overridden, though.
|
||||
The default is empty.
|
||||
|
||||
* **pod_environment_secret**
|
||||
similar to pod_environment_configmap but referencing a secret with custom
|
||||
environment variables. Because the secret is not allowed to exist in a
|
||||
different namespace than a Postgres cluster you can only use it in a single
|
||||
namespace. The default is empty.
|
||||
|
||||
* **pod_priority_class_name**
|
||||
a name of the [priority class](https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass)
|
||||
|
|
@ -401,18 +559,32 @@ configuration they are grouped under the `kubernetes` key.
|
|||
override [topology key](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#built-in-node-labels)
|
||||
for pod anti affinity. The default is `kubernetes.io/hostname`.
|
||||
|
||||
* **pod_antiaffinity_preferred_during_scheduling**
|
||||
when scaling the number of pods beyond the available number of topology
|
||||
keys the anti affinity has to be configured to preferred during scheduling.
|
||||
The default is `false` which means the pod anti affinity will use
|
||||
`requiredDuringSchedulingIgnoredDuringExecution`.
|
||||
|
||||
* **pod_management_policy**
|
||||
specify the [pod management policy](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies)
|
||||
of stateful sets of PG clusters. The default is `ordered_ready`, the second
|
||||
possible value is `parallel`.
|
||||
|
||||
* **enable_readiness_probe**
|
||||
the operator can set a readiness probe on the statefulset for the database
|
||||
pods with `InitialDelaySeconds: 6`, `PeriodSeconds: 10`, `TimeoutSeconds: 5`,
|
||||
`SuccessThreshold: 1` and `FailureThreshold: 3`. When enabling readiness
|
||||
probes it is recommended to switch the `pod_management_policy` to `parallel`
|
||||
to avoid unnecessary waiting times in case of multiple instances failing.
|
||||
The default is `false`.
|
||||
|
||||
* **storage_resize_mode**
|
||||
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
|
||||
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
|
||||
|
|
@ -423,27 +595,46 @@ CRD-based configuration.
|
|||
|
||||
* **default_cpu_request**
|
||||
CPU request value for the Postgres containers, unless overridden by
|
||||
cluster-specific settings. The default is `100m`.
|
||||
cluster-specific settings. Empty string or `0` disables the default.
|
||||
|
||||
* **default_memory_request**
|
||||
memory request value for the Postgres containers, unless overridden by
|
||||
cluster-specific settings. The default is `100Mi`.
|
||||
cluster-specific settings. Empty string or `0` disables the default.
|
||||
|
||||
* **default_cpu_limit**
|
||||
CPU limits for the Postgres containers, unless overridden by cluster-specific
|
||||
settings. The default is `1`.
|
||||
settings. Empty string or `0` disables the default.
|
||||
|
||||
* **default_memory_limit**
|
||||
memory limits for the Postgres containers, unless overridden by cluster-specific
|
||||
settings. The default is `500Mi`.
|
||||
settings. Empty string or `0` disables the default.
|
||||
|
||||
* **max_cpu_request**
|
||||
optional upper boundary for CPU request
|
||||
|
||||
* **max_memory_request**
|
||||
optional upper boundary for memory request
|
||||
|
||||
* **min_cpu_limit**
|
||||
hard CPU minimum what we consider to be required to properly run Postgres
|
||||
clusters with Patroni on Kubernetes. The default is `250m`.
|
||||
clusters with Patroni on Kubernetes.
|
||||
|
||||
* **min_memory_limit**
|
||||
hard memory minimum what we consider to be required to properly run Postgres
|
||||
clusters with Patroni on Kubernetes. The default is `250Mi`.
|
||||
clusters with Patroni on Kubernetes.
|
||||
|
||||
## Patroni options
|
||||
|
||||
Parameters configuring Patroni. In the CRD-based configuration they are grouped
|
||||
under the `patroni` key.
|
||||
|
||||
* **enable_patroni_failsafe_mode**
|
||||
If enabled, Patroni copes with DCS outages by avoiding leader demotion.
|
||||
See the Patroni documentation [here](https://patroni.readthedocs.io/en/master/dcs_failsafe_mode.html) for more details.
|
||||
This feature is included since Patroni 3.0.0. Hence, check the container image
|
||||
in use if this feature is included in the used Patroni version. It can also be
|
||||
enabled cluster-wise with the `failsafe_mode` flag under the `patroni` section
|
||||
in the manifest. The default for the global config option is set to `false`.
|
||||
|
||||
## Operator timeouts
|
||||
|
||||
|
|
@ -453,6 +644,13 @@ configuration `resource_check_interval` and `resource_check_timeout` have no
|
|||
effect, and the parameters are grouped under the `timeouts` key in the
|
||||
CRD-based configuration.
|
||||
|
||||
* **PatroniAPICheckInterval**
|
||||
the interval between consecutive attempts waiting for the return of
|
||||
Patroni Api. The default is `1s`.
|
||||
|
||||
* **PatroniAPICheckTimeout**
|
||||
the timeout for a response from Patroni Api. The default is `5s`.
|
||||
|
||||
* **resource_check_interval**
|
||||
interval to wait between consecutive attempts to check for the presence of
|
||||
some Kubernetes resource (i.e. `StatefulSet` or `PodDisruptionBudget`). The
|
||||
|
|
@ -501,27 +699,62 @@ In the CRD-based configuration they are grouped under the `load_balancer` key.
|
|||
toggles service type load balancer pointing to the master pod of the cluster.
|
||||
Can be overridden by individual cluster settings. The default is `true`.
|
||||
|
||||
* **enable_replica_load_balancer**
|
||||
toggles service type load balancer pointing to the replica pod of the
|
||||
cluster. Can be overridden by individual cluster settings. The default is
|
||||
* **enable_master_pooler_load_balancer**
|
||||
toggles service type load balancer pointing to the master pooler pod of the
|
||||
cluster. Can be overridden by individual cluster settings. The default is
|
||||
`false`.
|
||||
|
||||
* **external_traffic_policy** defines external traffic policy for load
|
||||
* **enable_replica_load_balancer**
|
||||
toggles service type load balancer pointing to the replica pod(s) of the
|
||||
cluster. Can be overridden by individual cluster settings. The default is
|
||||
`false`.
|
||||
|
||||
* **enable_replica_pooler_load_balancer**
|
||||
toggles service type load balancer pointing to the replica pooler pod(s) of
|
||||
the cluster. Can be overridden by individual cluster settings. The default
|
||||
is `false`.
|
||||
|
||||
* **external_traffic_policy**
|
||||
defines external traffic policy for load
|
||||
balancers. Allowed values are `Cluster` (default) and `Local`.
|
||||
|
||||
* **master_dns_name_format** defines the DNS name string template for the
|
||||
master load balancer cluster. The default is
|
||||
`{cluster}.{team}.{hostedzone}`, where `{cluster}` is replaced by the cluster
|
||||
name, `{team}` is replaced with the team name and `{hostedzone}` is replaced
|
||||
with the hosted zone (the value of the `db_hosted_zone` parameter). No other
|
||||
placeholders are allowed.
|
||||
* **master_dns_name_format**
|
||||
defines the DNS name string template for the master load balancer cluster.
|
||||
The default is `{cluster}.{namespace}.{hostedzone}`, where `{cluster}` is
|
||||
replaced by the cluster name, `{namespace}` is replaced with the namespace
|
||||
and `{hostedzone}` is replaced with the hosted zone (the value of the
|
||||
`db_hosted_zone` parameter). The `{team}` placeholder can still be used,
|
||||
although it is not recommended because the team of a cluster can change.
|
||||
If the cluster name starts with the `teamId` it will also be part of the
|
||||
DNS, aynway. No other placeholders are allowed!
|
||||
|
||||
* **replica_dns_name_format** defines the DNS name string template for the
|
||||
replica load balancer cluster. The default is
|
||||
`{cluster}-repl.{team}.{hostedzone}`, where `{cluster}` is replaced by the
|
||||
cluster name, `{team}` is replaced with the team name and `{hostedzone}` is
|
||||
replaced with the hosted zone (the value of the `db_hosted_zone` parameter).
|
||||
No other placeholders are allowed.
|
||||
* **master_legacy_dns_name_format**
|
||||
*deprecated* default master DNS template `{cluster}.{team}.{hostedzone}` as
|
||||
of pre `v1.9.0`. If cluster name starts with `teamId` then a second DNS
|
||||
entry will be created using the template defined here to provide backwards
|
||||
compatibility. The `teamId` prefix will be extracted from the clustername
|
||||
because it follows later in the DNS string. When using a customized
|
||||
`master_dns_name_format` make sure to define the legacy DNS format when
|
||||
switching to v1.9.0.
|
||||
|
||||
* **replica_dns_name_format**
|
||||
defines the DNS name string template for the replica load balancer cluster.
|
||||
The default is `{cluster}-repl.{namespace}.{hostedzone}`, where `{cluster}`
|
||||
is replaced by the cluster name, `{namespace}` is replaced with the
|
||||
namespace and `{hostedzone}` is replaced with the hosted zone (the value of
|
||||
the `db_hosted_zone` parameter). The `{team}` placeholder can still be used,
|
||||
although it is not recommended because the team of a cluster can change.
|
||||
If the cluster name starts with the `teamId` it will also be part of the
|
||||
DNS, aynway. No other placeholders are allowed!
|
||||
|
||||
* **replica_legacy_dns_name_format**
|
||||
*deprecated* default master DNS template `{cluster}-repl.{team}.{hostedzone}`
|
||||
as of pre `v1.9.0`. If cluster name starts with `teamId` then a second DNS
|
||||
entry will be created using the template defined here to provide backwards
|
||||
compatibility. The `teamId` prefix will be extracted from the clustername
|
||||
because it follows later in the DNS string. When using a customized
|
||||
`master_dns_name_format` make sure to define the legacy DNS format when
|
||||
switching to v1.9.0.
|
||||
|
||||
## AWS or GCP interaction
|
||||
|
||||
|
|
@ -550,6 +783,12 @@ yet officially supported.
|
|||
[service accounts](https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform).
|
||||
The default is empty
|
||||
|
||||
* **wal_az_storage_account**
|
||||
Azure Storage Account to use for shipping WAL segments with WAL-G. The
|
||||
storage account must exist and be accessible by Postgres pods. Note, only the
|
||||
name of the storage account is required.
|
||||
The default is empty.
|
||||
|
||||
* **log_s3_bucket**
|
||||
S3 bucket to use for shipping Postgres daily logs. Works only with S3 on AWS.
|
||||
The bucket has to be present and accessible by Postgres pods. The default is
|
||||
|
|
@ -562,7 +801,10 @@ yet officially supported.
|
|||
empty.
|
||||
|
||||
* **aws_region**
|
||||
AWS region used to store EBS volumes. The default is `eu-central-1`.
|
||||
AWS region used to store EBS volumes. The default is `eu-central-1`. Note,
|
||||
this option is not meant for specifying the AWS region for backups and
|
||||
restore, since it can be separate from the EBS region. You have to define
|
||||
AWS_REGION as a [custom environment variable](../administrator.md#custom-pod-environment-variables).
|
||||
|
||||
* **additional_secret_mount**
|
||||
Additional Secret (aws or gcp credentials) to mount in the pod.
|
||||
|
|
@ -588,12 +830,19 @@ These parameters configure a K8s cron job managed by the operator to produce
|
|||
Postgres logical backups. In the CRD-based configuration those parameters are
|
||||
grouped under the `logical_backup` key.
|
||||
|
||||
* **logical_backup_cpu_limit**
|
||||
**logical_backup_cpu_request**
|
||||
**logical_backup_memory_limit**
|
||||
**logical_backup_memory_request**
|
||||
Resource configuration for pod template in logical backup cron job. If empty
|
||||
default values from `postgres_pod_resources` will be used.
|
||||
|
||||
* **logical_backup_docker_image**
|
||||
An image for pods of the logical backup job. The [example image](../../docker/logical-backup/Dockerfile)
|
||||
An image for pods of the logical backup job. The [example image](https://github.com/zalando/postgres-operator/blob/master/logical-backup/Dockerfile)
|
||||
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`.
|
||||
an S3 bucket under the key `/<configured-s3-bucket-prefix>/<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.3"
|
||||
pipeline. Default: "ghcr.io/zalando/postgres-operator/logical-backup:v1.15.1"
|
||||
|
||||
* **logical_backup_google_application_credentials**
|
||||
Specifies the path of the google cloud service account json file. Default is empty.
|
||||
|
|
@ -602,8 +851,17 @@ grouped under the `logical_backup` key.
|
|||
The prefix to be prepended to the name of a k8s CronJob running the backups. Beware the prefix counts towards the name length restrictions imposed by k8s. Empty string is a legitimate value. Operator does not do the actual renaming: It simply creates the job with the new prefix. You will have to delete the old cron job manually. Default: "logical-backup-".
|
||||
|
||||
* **logical_backup_provider**
|
||||
Specifies the storage provider to which the backup should be uploaded (`s3` or `gcs`).
|
||||
Default: "s3"
|
||||
Specifies the storage provider to which the backup should be uploaded
|
||||
(`s3`, `gcs` or `az`). Default: "s3"
|
||||
|
||||
* **logical_backup_azure_storage_account_name**
|
||||
Storage account name used to upload logical backups to when using Azure. Default: ""
|
||||
|
||||
* **logical_backup_azure_storage_container**
|
||||
Storage container used to upload logical backups to when using Azure. Default: ""
|
||||
|
||||
* **logical_backup_azure_storage_account_key**
|
||||
Storage account key used to authenticate with Azure when uploading logical backups. Default: ""
|
||||
|
||||
* **logical_backup_s3_access_key_id**
|
||||
When set, value will be in AWS_ACCESS_KEY_ID env variable. The Default is empty.
|
||||
|
|
@ -612,6 +870,9 @@ grouped under the `logical_backup` key.
|
|||
S3 bucket to store backup results. The bucket has to be present and
|
||||
accessible by Postgres pods. Default: empty.
|
||||
|
||||
* **logical_backup_s3_bucket_prefix**
|
||||
S3 bucket prefix to use in configured bucket. Default: "spilo"
|
||||
|
||||
* **logical_backup_s3_endpoint**
|
||||
When using non-AWS S3 storage, endpoint can be set as a ENV variable. The default is empty.
|
||||
|
||||
|
|
@ -625,11 +886,41 @@ grouped under the `logical_backup` key.
|
|||
Specify server side encryption that S3 storage is using. If empty string
|
||||
is specified, no argument will be passed to `aws s3` command. Default: "AES256".
|
||||
|
||||
* **logical_backup_s3_retention_time**
|
||||
Specify a retention time for logical backups stored in S3. Backups older than the specified retention
|
||||
time will be deleted after a new backup was uploaded. If empty, all backups will be kept. Example values are
|
||||
"3 days", "2 weeks", or "1 month". The default is empty.
|
||||
|
||||
* **logical_backup_schedule**
|
||||
Backup schedule in the cron format. Please take the
|
||||
[reference schedule format](https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#schedule)
|
||||
into account. Default: "30 00 \* \* \*"
|
||||
|
||||
* **logical_backup_cronjob_environment_secret**
|
||||
Reference to a Kubernetes secret, which keys will be added as environment variables to the cronjob. Default: ""
|
||||
|
||||
* **logical_backup_successful_jobs_history_limit**
|
||||
number of successful backup jobs to keep in cronjob history. The default is `3`.
|
||||
|
||||
* **logical_backup_failed_jobs_history_limit**
|
||||
number of failed backup jobs to keep in cronjob history. The default is `3`.
|
||||
|
||||
* **logical_backup_ttl_seconds_after_finished**
|
||||
TTL in seconds after which finished backup jobs are automatically deleted. The default is `86400`.
|
||||
|
||||
The following environment variables can be passed to the logical backup
|
||||
cronjob via `logical_backup_cronjob_environment_secret` to control
|
||||
connectivity checks before the backup starts:
|
||||
|
||||
* **LOGICAL_BACKUP_CONNECT_RETRIES**
|
||||
Number of times to retry connecting to the target PostgreSQL pod before
|
||||
giving up. This is useful when NetworkPolicy enforcement introduces a
|
||||
short delay before a newly-created pod's IP is allowed through ingress
|
||||
rules on the destination node. Default: "10"
|
||||
|
||||
* **LOGICAL_BACKUP_CONNECT_RETRY_DELAY**
|
||||
Delay in seconds between connectivity retries. Default: "2"
|
||||
|
||||
## Debugging the operator
|
||||
|
||||
Options to aid debugging of the operator itself. Grouped under the `debug` key.
|
||||
|
|
@ -697,7 +988,7 @@ key.
|
|||
|
||||
* **protected_role_names**
|
||||
List of roles that cannot be overwritten by an application, team or
|
||||
infrastructure role. The default is `admin`.
|
||||
infrastructure role. The default list is `admin` and `cron_admin`.
|
||||
|
||||
* **postgres_superuser_teams**
|
||||
List of teams which members need the superuser role in each PG database
|
||||
|
|
@ -792,7 +1083,7 @@ operator being able to provide some reasonable defaults.
|
|||
|
||||
* **connection_pooler_image**
|
||||
Docker image to use for connection pooler deployment.
|
||||
Default: "registry.opensource.zalan.do/acid/pgbouncer"
|
||||
Default: "ghcr.io/zalando/postgres-operator/pgbouncer:latest"
|
||||
|
||||
* **connection_pooler_max_db_connections**
|
||||
How many connections the pooler can max hold. This value is divided among the
|
||||
|
|
@ -806,5 +1097,4 @@ operator being able to provide some reasonable defaults.
|
|||
**connection_pooler_default_memory_reques**
|
||||
**connection_pooler_default_cpu_limit**
|
||||
**connection_pooler_default_memory_limit**
|
||||
Default resource configuration for connection pooler deployment. The internal
|
||||
default for memory request and limit is `100Mi`, for CPU it is `500m` and `1`.
|
||||
Default resource configuration for connection pooler deployment.
|
||||
|
|
|
|||
474
docs/user.md
474
docs/user.md
|
|
@ -5,7 +5,7 @@ Learn how to work with the Postgres Operator in a Kubernetes (K8s) environment.
|
|||
## Create a manifest for a new PostgreSQL cluster
|
||||
|
||||
Make sure you have [set up](quickstart.md) the operator. Then you can create a
|
||||
new Postgres cluster by applying manifest like this [minimal example](../manifests/minimal-postgres-manifest.yaml):
|
||||
new Postgres cluster by applying manifest like this [minimal example](https://github.com/zalando/postgres-operator/blob/master/manifests/minimal-postgres-manifest.yaml):
|
||||
|
||||
```yaml
|
||||
apiVersion: "acid.zalan.do/v1"
|
||||
|
|
@ -30,7 +30,7 @@ spec:
|
|||
databases:
|
||||
foo: zalando
|
||||
postgresql:
|
||||
version: "13"
|
||||
version: "18"
|
||||
```
|
||||
|
||||
Once you cloned the Postgres Operator [repository](https://github.com/zalando/postgres-operator)
|
||||
|
|
@ -45,11 +45,12 @@ Make sure, the `spec` section of the manifest contains at least a `teamId`, the
|
|||
The minimum volume size to run the `postgresql` resource on Elastic Block
|
||||
Storage (EBS) is `1Gi`.
|
||||
|
||||
Note, that the name of the cluster must start with the `teamId` and `-`. At
|
||||
Zalando we use team IDs (nicknames) to lower the chance of duplicate cluster
|
||||
names and colliding entities. The team ID would also be used to query an API to
|
||||
get all members of a team and create [database roles](#teams-api-roles) for
|
||||
them. Besides, the maximum cluster name length is 53 characters.
|
||||
Note, that when `enable_team_id_clustername_prefix` is set to `true` the name
|
||||
of the cluster must start with the `teamId` and `-`. At Zalando we use team IDs
|
||||
(nicknames) to lower chances of duplicate cluster names and colliding entities.
|
||||
The team ID would also be used to query an API to get all members of a team
|
||||
and create [database roles](#teams-api-roles) for them. Besides, the maximum
|
||||
cluster name length is 53 characters.
|
||||
|
||||
## Watch pods being created
|
||||
|
||||
|
|
@ -83,16 +84,33 @@ kubectl port-forward $PGMASTER 6432:5432 -n default
|
|||
```
|
||||
|
||||
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`:
|
||||
When connecting with a manifest role like `foo_user` user, read its password
|
||||
from the K8s secret which was generated when creating `acid-minimal-cluster`.
|
||||
As non-encrypted connections are rejected by default set SSL mode to `require`:
|
||||
|
||||
```bash
|
||||
export PGPASSWORD=$(kubectl get secret postgres.acid-minimal-cluster.credentials -o 'jsonpath={.data.password}' | base64 -d)
|
||||
export PGPASSWORD=$(kubectl get secret postgres.acid-minimal-cluster.credentials.postgresql.acid.zalan.do -o 'jsonpath={.data.password}' | base64 -d)
|
||||
export PGSSLMODE=require
|
||||
psql -U postgres -h localhost -p 6432
|
||||
```
|
||||
|
||||
## Password encryption
|
||||
|
||||
Passwords are encrypted using the `scram-sha-256` hashing method by default. Other methods can be configured by changing the `password_encryption` parameter in the cluster manifest:
|
||||
|
||||
```yaml
|
||||
apiVersion: "acid.zalan.do/v1"
|
||||
kind: postgresql
|
||||
metadata:
|
||||
name: acid-minimal-cluster
|
||||
spec:
|
||||
[...]
|
||||
postgresql:
|
||||
version: "18"
|
||||
parameters:
|
||||
password_encryption: scram-sha-256
|
||||
```
|
||||
|
||||
## Defining database roles in the operator
|
||||
|
||||
Postgres Operator allows defining roles to be created in the resulting database
|
||||
|
|
@ -113,7 +131,7 @@ chapter.
|
|||
### Manifest roles
|
||||
|
||||
Manifest roles are defined directly in the cluster manifest. See
|
||||
[minimal postgres manifest](../manifests/minimal-postgres-manifest.yaml)
|
||||
[minimal postgres manifest](https://github.com/zalando/postgres-operator/blob/master/manifests/minimal-postgres-manifest.yaml)
|
||||
for an example of `zalando` role, defined with `superuser` and `createdb` flags.
|
||||
|
||||
Manifest roles are defined as a dictionary, with a role name as a key and a
|
||||
|
|
@ -131,7 +149,7 @@ specified explicitly.
|
|||
|
||||
The operator automatically generates a password for each manifest role and
|
||||
places it in the secret named
|
||||
`{username}.{team}-{clustername}.credentials.postgresql.acid.zalan.do` in the
|
||||
`{username}.{clustername}.credentials.postgresql.acid.zalan.do` in the
|
||||
same namespace as the cluster. This way, the application running in the
|
||||
K8s cluster and connecting to Postgres can obtain the password right from the
|
||||
secret, without ever sharing it outside of the cluster.
|
||||
|
|
@ -139,6 +157,30 @@ secret, without ever sharing it outside of the cluster.
|
|||
At the moment it is not possible to define membership of the manifest role in
|
||||
other roles.
|
||||
|
||||
To define the secrets for the users in a different namespace than that of the
|
||||
cluster, one can set `enable_cross_namespace_secret` and declare the namespace
|
||||
for the secrets in the manifest in the following manner (note, that it has to
|
||||
be reflected in the `database` section, too),
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
users:
|
||||
# users with secret in different namespace
|
||||
appspace.db_user:
|
||||
- createdb
|
||||
databases:
|
||||
# namespace notation is part of user name
|
||||
app_db: appspace.db_user
|
||||
```
|
||||
|
||||
Here, anything before the first dot is considered the namespace and the text after
|
||||
the first dot is the username. Also, the postgres roles of these usernames would
|
||||
be in the form of `namespace.username`.
|
||||
|
||||
For such usernames, the secret is created in the given namespace and its name is
|
||||
of the following form,
|
||||
`{namespace}.{username}.{clustername}.credentials.postgresql.acid.zalan.do`
|
||||
|
||||
### Infrastructure roles
|
||||
|
||||
An infrastructure role is a role that should be present on every PostgreSQL
|
||||
|
|
@ -178,7 +220,7 @@ the user name, password etc. The secret itself is referenced by the
|
|||
above list them separately.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
apiVersion: "acid.zalan.do/v1"
|
||||
kind: OperatorConfiguration
|
||||
metadata:
|
||||
name: postgresql-operator-configuration
|
||||
|
|
@ -198,7 +240,7 @@ Note, only the CRD-based configuration allows for referencing multiple secrets.
|
|||
As of now, the ConfigMap is restricted to either one or the existing template
|
||||
option with `infrastructure_roles_secret_name`. Please, refer to the example
|
||||
manifests to understand how `infrastructure_roles_secrets` has to be configured
|
||||
for the [configmap](../manifests/configmap.yaml) or [CRD configuration](../manifests/postgresql-operator-default-configuration.yaml).
|
||||
for the [configmap](https://github.com/zalando/postgres-operator/blob/master/manifests/configmap.yaml) or [CRD configuration](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresql-operator-default-configuration.yaml).
|
||||
|
||||
If both `infrastructure_roles_secret_name` and `infrastructure_roles_secrets`
|
||||
are defined the operator will create roles for both of them. So make sure,
|
||||
|
|
@ -243,8 +285,8 @@ Since an infrastructure role is created uniformly on all clusters managed by
|
|||
the operator, it makes no sense to define it without the password. Such
|
||||
definitions will be ignored with a prior warning.
|
||||
|
||||
See [infrastructure roles secret](../manifests/infrastructure-roles.yaml)
|
||||
and [infrastructure roles configmap](../manifests/infrastructure-roles-configmap.yaml)
|
||||
See [infrastructure roles secret](https://github.com/zalando/postgres-operator/blob/master/manifests/infrastructure-roles.yaml)
|
||||
and [infrastructure roles configmap](https://github.com/zalando/postgres-operator/blob/master/manifests/infrastructure-roles-configmap.yaml)
|
||||
for the examples.
|
||||
|
||||
### Teams API roles
|
||||
|
|
@ -260,7 +302,7 @@ returns usernames. A minimal Teams API should work like this:
|
|||
/.../<teamname> -> ["name","anothername"]
|
||||
```
|
||||
|
||||
A ["fake" Teams API](../manifests/fake-teams-api.yaml) deployment is provided
|
||||
A ["fake" Teams API](https://github.com/zalando/postgres-operator/blob/master/manifests/fake-teams-api.yaml) deployment is provided
|
||||
in the manifests folder to set up a basic API around whatever services is used
|
||||
for user management. The Teams API's URL is set in the operator's
|
||||
[configuration](reference/operator_parameters.md#automatic-creation-of-human-users-in-the-database)
|
||||
|
|
@ -275,12 +317,12 @@ Postgres clusters are associated with one team by providing the `teamID` in
|
|||
the manifest. Additional superuser teams can be configured as mentioned in
|
||||
the previous paragraph. However, this is a global setting. To assign
|
||||
additional teams, superuser teams and single users to clusters of a given
|
||||
team, use the [PostgresTeam CRD](../manifests/postgresteam.crd.yaml).
|
||||
team, use the [PostgresTeam CRD](https://github.com/zalando/postgres-operator/blob/master/manifests/postgresteam.crd.yaml).
|
||||
|
||||
Note, by default the `PostgresTeam` support is disabled in the configuration.
|
||||
Switch `enable_postgres_team_crd` flag to `true` and the operator will start to
|
||||
watch for this CRD. Make sure, the cluster role is up to date and contains a
|
||||
section for [PostgresTeam](../manifests/operator-service-account-rbac.yaml#L30).
|
||||
section for [PostgresTeam](https://github.com/zalando/postgres-operator/blob/master/manifests/operator-service-account-rbac.yaml#L30).
|
||||
|
||||
#### Additional teams
|
||||
|
||||
|
|
@ -330,7 +372,7 @@ spec:
|
|||
|
||||
This creates roles for members of the `c-team` team not only in all clusters
|
||||
owned by `a-team`, but as well in cluster owned by `b-team`, as `a-team` is
|
||||
an `additionalTeam` to `b-team`
|
||||
an `additionalTeam` to `b-team`
|
||||
|
||||
Not, you can also define `additionalSuperuserTeams` in the `PostgresTeam`
|
||||
manifest. By default, this option is disabled and must be configured with
|
||||
|
|
@ -472,7 +514,7 @@ Postgres Operator will create the following NOLOGIN roles:
|
|||
|
||||
The `<dbname>_owner` role is the database owner and should be used when creating
|
||||
new database objects. All members of the `admin` role, e.g. teams API roles, can
|
||||
become the owner with the `SET ROLE` command. [Default privileges](https://www.postgresql.org/docs/12/sql-alterdefaultprivileges.html)
|
||||
become the owner with the `SET ROLE` command. [Default privileges](https://www.postgresql.org/docs/18/sql-alterdefaultprivileges.html)
|
||||
are configured for the owner role so that the `<dbname>_reader` role
|
||||
automatically gets read-access (SELECT) to new tables and sequences and the
|
||||
`<dbname>_writer` receives write-access (INSERT, UPDATE, DELETE on tables,
|
||||
|
|
@ -501,9 +543,10 @@ Then, the schemas are owned by the database owner, too.
|
|||
|
||||
The roles described in the previous paragraph can be granted to LOGIN roles from
|
||||
the `users` section in the manifest. Optionally, the Postgres Operator can also
|
||||
create default LOGIN roles for the database an each schema individually. These
|
||||
create default LOGIN roles for the database and each schema individually. These
|
||||
roles will get the `_user` suffix and they inherit all rights from their NOLOGIN
|
||||
counterparts.
|
||||
counterparts. Therefore, you cannot have `defaultRoles` set to `false` and enable
|
||||
`defaultUsers` at the same time.
|
||||
|
||||
| Role name | Member of | Admin |
|
||||
| ------------------- | -------------- | ------------- |
|
||||
|
|
@ -526,9 +569,29 @@ spec:
|
|||
defaultUsers: true
|
||||
```
|
||||
|
||||
Default access privileges are also defined for LOGIN roles on database and
|
||||
schema creation. This means they are currently not set when `defaultUsers`
|
||||
(or `defaultRoles` for schemas) are enabled at a later point in time.
|
||||
|
||||
For all LOGIN roles the operator will create K8s secrets in the namespace
|
||||
specified in `secretNamespace`, if `enable_cross_namespace_secret` is set to
|
||||
`true` in the config. Otherwise, they are created in the same namespace like
|
||||
the Postgres cluster. Unlike roles specified with `namespace.username` under
|
||||
`users`, the namespace will not be part of the role name here. Keep in mind
|
||||
that the underscores in a role name are replaced with dashes in the K8s
|
||||
secret name.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
preparedDatabases:
|
||||
foo:
|
||||
defaultUsers: true
|
||||
secretNamespace: appspace
|
||||
```
|
||||
|
||||
### Schema `search_path` for default roles
|
||||
|
||||
The schema [`search_path`](https://www.postgresql.org/docs/13/ddl-schemas.html#DDL-SCHEMAS-PATH)
|
||||
The schema [`search_path`](https://www.postgresql.org/docs/18/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
|
||||
|
|
@ -560,10 +623,9 @@ spec:
|
|||
```
|
||||
|
||||
Some extensions require SUPERUSER rights on creation unless they are not
|
||||
whitelisted by the [pgextwlist](https://github.com/dimitri/pgextwlist)
|
||||
extension, that is shipped with the Spilo image. To see which extensions are
|
||||
on the list check the `extwlist.extension` parameter in the postgresql.conf
|
||||
file.
|
||||
allowed by the [pgextwlist](https://github.com/dimitri/pgextwlist) extension,
|
||||
that is shipped with the Spilo image. To see which extensions are on the list
|
||||
check the `extwlist.extension` parameter in the postgresql.conf file.
|
||||
|
||||
```bash
|
||||
SHOW extwlist.extensions;
|
||||
|
|
@ -624,12 +686,38 @@ The minimum limits to properly run the `postgresql` resource are configured to
|
|||
manifest the operator will raise the limits to the configured minimum values.
|
||||
If no resources are defined in the manifest they will be obtained from the
|
||||
configured [default requests](reference/operator_parameters.md#kubernetes-resource-requests).
|
||||
If neither defaults nor minimum limits are configured the operator will not
|
||||
specify any resources and it's up to K8s (or your own) admission hooks to
|
||||
handle it.
|
||||
|
||||
## Use taints, tolerations and node affinity for dedicated PostgreSQL nodes
|
||||
### HugePages support
|
||||
|
||||
The operator supports [HugePages](https://www.postgresql.org/docs/18/kernel-resources.html#LINUX-HUGEPAGES).
|
||||
To enable HugePages, set the matching resource requests and/or limits in the manifest:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
resources:
|
||||
requests:
|
||||
hugepages-2Mi: 250Mi
|
||||
hugepages-1Gi: 1Gi
|
||||
limits:
|
||||
hugepages-2Mi: 500Mi
|
||||
hugepages-1Gi: 2Gi
|
||||
```
|
||||
|
||||
There are no minimums or maximums and the default is 0 for both HugePage sizes,
|
||||
but Kubernetes will not spin up the pod if the requested HugePages cannot be allocated.
|
||||
For more information on HugePages in Kubernetes, see also
|
||||
[https://kubernetes.io/docs/tasks/manage-hugepages/scheduling-hugepages/](https://kubernetes.io/docs/tasks/manage-hugepages/scheduling-hugepages/)
|
||||
|
||||
## Use taints, tolerations, node affinity and topology spread constraint for dedicated PostgreSQL nodes
|
||||
|
||||
To ensure Postgres pods are running on nodes without any other application pods,
|
||||
you can use [taints and tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)
|
||||
and configure the required toleration in the manifest.
|
||||
and configure the required toleration in the manifest. Tolerations can also be
|
||||
defined in the [operator config](administrator.md#use-taints-and-tolerations-for-dedicated-postgresql-nodes)
|
||||
to apply for all Postgres clusters.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
|
|
@ -661,10 +749,30 @@ spec:
|
|||
- pci
|
||||
```
|
||||
|
||||
If you need to define a `nodeAffinity` for all your Postgres clusters use the
|
||||
`node_readiness_label` [configuration](administrator.md#node-readiness-labels).
|
||||
|
||||
If you need PostgreSQL Pods to run on separate nodes, you can use the
|
||||
[topologySpreadConstraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/) to control how they are distributed across your cluster.
|
||||
This ensures they are spread among failure domains such as
|
||||
regions, zones, nodes, or other user-defined topology domains.
|
||||
|
||||
```yaml
|
||||
apiVersion: "acid.zalan.do/v1"
|
||||
kind: postgresql
|
||||
metadata:
|
||||
name: acid-minimal-cluster
|
||||
spec:
|
||||
topologySpreadConstraints:
|
||||
- maxskew: 1
|
||||
topologyKey: topology.kubernetes.io/zone
|
||||
whenUnsatisfiable: DoNotSchedule
|
||||
```
|
||||
|
||||
## 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,
|
||||
Starting with Spilo 14, operator supports in-place major version upgrade to a
|
||||
higher major version (e.g. from PG 14 to PG 16). 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
|
||||
|
|
@ -690,28 +798,41 @@ source cluster. If you create it in the same Kubernetes environment, use a
|
|||
different name.
|
||||
|
||||
```yaml
|
||||
apiVersion: "acid.zalan.do/v1"
|
||||
kind: postgresql
|
||||
metadata:
|
||||
name: acid-minimal-cluster-clone
|
||||
spec:
|
||||
clone:
|
||||
uid: "efd12e58-5786-11e8-b5a7-06148230260c"
|
||||
cluster: "acid-batman"
|
||||
timestamp: "2017-12-19T12:40:33+01:00"
|
||||
cluster: "acid-minimal-cluster"
|
||||
timestamp: "2025-12-19T12:40:33+01:00"
|
||||
```
|
||||
|
||||
Here `cluster` is a name of a source cluster that is going to be cloned. A new
|
||||
cluster will be cloned from S3, using the latest backup before the `timestamp`.
|
||||
Note, that a time zone is required for `timestamp` in the format of +00:00 which
|
||||
is UTC. The `uid` field is also mandatory. The operator will use it to find a
|
||||
correct key inside an S3 bucket. You can find this field in the metadata of the
|
||||
source cluster:
|
||||
Note, a time zone is required for `timestamp` in the format of `+00:00` (UTC).
|
||||
|
||||
The operator will try to find the WAL location based on the configured
|
||||
`wal_[s3|gs]_bucket` or `wal_az_storage_account` and the specified `uid`.
|
||||
You can find the UID of the source cluster in its metadata:
|
||||
|
||||
```yaml
|
||||
apiVersion: acid.zalan.do/v1
|
||||
kind: postgresql
|
||||
metadata:
|
||||
name: acid-test-cluster
|
||||
name: acid-minimal-cluster
|
||||
uid: efd12e58-5786-11e8-b5a7-06148230260c
|
||||
```
|
||||
|
||||
If your source cluster uses a WAL location different from the global
|
||||
configuration you can specify the full path under `s3_wal_path`. For
|
||||
[Google Cloud Platform](administrator.md#google-cloud-platform-setup)
|
||||
or [Azure](administrator.md#azure-setup)
|
||||
it can only be set globally with [custom Pod environment variables](administrator.md#custom-pod-environment-variables)
|
||||
or locally in the Postgres manifest's [`env`](administrator.md#via-postgres-cluster-manifest) section.
|
||||
|
||||
|
||||
For non AWS S3 following settings can be set to support cloning from other S3
|
||||
implementations:
|
||||
|
||||
|
|
@ -719,8 +840,9 @@ implementations:
|
|||
spec:
|
||||
clone:
|
||||
uid: "efd12e58-5786-11e8-b5a7-06148230260c"
|
||||
cluster: "acid-batman"
|
||||
timestamp: "2017-12-19T12:40:33+01:00"
|
||||
cluster: "acid-minimal-cluster"
|
||||
timestamp: "2025-12-19T12:40:33+01:00"
|
||||
s3_wal_path: "s3://custom/path/to/bucket"
|
||||
s3_endpoint: https://s3.acme.org
|
||||
s3_access_key_id: 0123456789abcdef0123456789abcdef
|
||||
s3_secret_access_key: 0123456789abcdef0123456789abcdef
|
||||
|
|
@ -730,7 +852,7 @@ spec:
|
|||
### Clone directly
|
||||
|
||||
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
|
||||
[pg_basebackup](https://www.postgresql.org/docs/18/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
|
||||
|
|
@ -740,89 +862,152 @@ namespace.
|
|||
```yaml
|
||||
spec:
|
||||
clone:
|
||||
cluster: "acid-batman"
|
||||
cluster: "acid-minimal-cluster"
|
||||
```
|
||||
|
||||
Be aware that on a busy source database this can result in an elevated load!
|
||||
|
||||
## Restore in place
|
||||
|
||||
There is also a possibility to restore a database without cloning it. The
|
||||
advantage to this is that there is no need to change anything on the
|
||||
application side. However, as it involves deleting the database first, this
|
||||
process is of course riskier than cloning (which involves adjusting the
|
||||
connection parameters of the app).
|
||||
|
||||
First, make sure there is no writing activity on your DB, and save the UID.
|
||||
Then delete the `postgresql` K8S resource:
|
||||
|
||||
```bash
|
||||
zkubectl delete postgresql acid-test-restore
|
||||
```
|
||||
|
||||
Then deploy a new manifest with the same name, referring to itself
|
||||
(both name and UID) in the `clone` section:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: acid-minimal-cluster
|
||||
# [...]
|
||||
spec:
|
||||
# [...]
|
||||
clone:
|
||||
cluster: "acid-minimal-cluster" # the same as metadata.name above!
|
||||
uid: "<original_UID>"
|
||||
timestamp: "2022-04-01T10:11:12.000+00:00"
|
||||
```
|
||||
|
||||
This will create a new database cluster with the same name but different UID,
|
||||
whereas the database will be in the state it was at the specified time.
|
||||
|
||||
:warning: The backups and WAL files for the original DB are retained under the
|
||||
original UID, making it possible retry restoring. However, it is probably
|
||||
better to create a temporary clone for experimenting or finding out to which
|
||||
point you should restore.
|
||||
|
||||
## Setting up a standby cluster
|
||||
|
||||
Standby cluster is a [Patroni feature](https://github.com/zalando/patroni/blob/master/docs/replica_bootstrap.rst#standby-cluster)
|
||||
that first clones a database, and keeps replicating changes afterwards. As the
|
||||
replication is happening by the means of archived WAL files (stored on S3 or
|
||||
the equivalent of other cloud providers), the standby cluster can exist in a
|
||||
different location than its source database. Unlike cloning, the PostgreSQL
|
||||
version between source and target cluster has to be the same.
|
||||
that first clones a database, and keeps replicating changes afterwards. It can
|
||||
exist in a different location than its source database, but unlike cloning,
|
||||
the PostgreSQL version between source and target cluster has to be the same.
|
||||
|
||||
To start a cluster as standby, add the following `standby` section in the YAML
|
||||
file and specify the S3 bucket path. An empty path will result in an error and
|
||||
no statefulset will be created.
|
||||
file. You can stream changes from archived WAL files (AWS S3 or Google Cloud
|
||||
Storage), from a remote primary, or combine a remote primary with a WAL archive.
|
||||
At least one of `s3_wal_path`, `gs_wal_path`, or `standby_host` must be specified.
|
||||
Note that `s3_wal_path` and `gs_wal_path` are mutually exclusive.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
standby:
|
||||
s3_wal_path: "s3 bucket path to the master"
|
||||
s3_wal_path: "s3://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>"
|
||||
```
|
||||
|
||||
At the moment, the operator only allows to stream from the WAL archive of the
|
||||
master. Thus, it is recommended to deploy standby clusters with only [one pod](../manifests/standby-manifest.yaml#L10).
|
||||
You can raise the instance count when detaching. Note, that the same pod role
|
||||
labels like for normal clusters are used: The standby leader is labeled as
|
||||
`master`.
|
||||
For GCS, you have to define STANDBY_GOOGLE_APPLICATION_CREDENTIALS as a
|
||||
[custom pod environment variable](administrator.md#custom-pod-environment-variables).
|
||||
It is not set from the config to allow for overriding.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
standby:
|
||||
gs_wal_path: "gs://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>"
|
||||
```
|
||||
|
||||
For a remote primary you specify the host address and optionally the port.
|
||||
If you leave out the port Patroni will use `"5432"`.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
standby:
|
||||
standby_host: "acid-minimal-cluster.default"
|
||||
standby_port: "5433"
|
||||
```
|
||||
|
||||
You can also combine a remote primary with a WAL archive for additional redundancy:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
standby:
|
||||
standby_host: "acid-minimal-cluster.default"
|
||||
standby_port: "5433"
|
||||
s3_wal_path: "s3://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>"
|
||||
```
|
||||
|
||||
Note, that the pods and services use the same role labels like for normal clusters:
|
||||
The standby leader is labeled as `master`. When using the `standby_host` option
|
||||
you have to copy the credentials from the source cluster's secrets to successfully
|
||||
bootstrap a standby cluster (see next chapter).
|
||||
|
||||
### Providing credentials of source cluster
|
||||
|
||||
A standby cluster is replicating the data (including users and passwords) from
|
||||
the source database and is read-only. The system and application users (like
|
||||
standby, postgres etc.) all have a password that does not match the credentials
|
||||
stored in secrets which are created by the operator. One solution is to create
|
||||
secrets beforehand and paste in the credentials of the source cluster.
|
||||
stored in secrets which are created by the operator. You have two options:
|
||||
|
||||
a. Create secrets manually beforehand and paste the credentials of the source
|
||||
cluster
|
||||
b. Let the operator create the secrets when it bootstraps the standby cluster.
|
||||
Patch the secrets with the credentials of the source cluster. Replace the
|
||||
spilo pods.
|
||||
|
||||
Otherwise, you will see errors in the Postgres logs saying users cannot log in
|
||||
and the operator logs will complain about not being able to sync resources.
|
||||
If you stream changes from a remote primary you have to align the secrets or
|
||||
the standby cluster will not start up.
|
||||
|
||||
When you only run a standby leader, you can safely ignore this, as it will be
|
||||
sorted out once the cluster is detached from the source. It is also harmless if
|
||||
you don’t plan it. But, when you created a standby replica, too, fix the
|
||||
credentials right away. WAL files will pile up on the standby leader if no
|
||||
connection can be established between standby replica(s). You can also edit the
|
||||
secrets after their creation. Find them by:
|
||||
|
||||
```bash
|
||||
kubectl get secrets --all-namespaces | grep <standby-cluster-name>
|
||||
```
|
||||
If you stream changes from WAL files and you only run a standby leader, you
|
||||
can safely ignore the secret mismatch, as it will be sorted out once the
|
||||
cluster is detached from the source. It is also harmless if you do not plan it.
|
||||
But, when you create a standby replica, too, fix the credentials right away.
|
||||
WAL files will pile up on the standby leader if no connection can be
|
||||
established between standby replica(s).
|
||||
|
||||
### Promote the standby
|
||||
|
||||
One big advantage of standby clusters is that they can be promoted to a proper
|
||||
database cluster. This means it will stop replicating changes from the source,
|
||||
and start accept writes itself. This mechanism makes it possible to move
|
||||
databases from one place to another with minimal downtime. Currently, the
|
||||
operator does not support promoting a standby cluster. It has to be done
|
||||
manually using `patronictl edit-config` inside the postgres container of the
|
||||
standby leader pod. Remove the following lines from the YAML structure and the
|
||||
leader promotion happens immediately. Before doing so, make sure that the
|
||||
standby is not behind the source database.
|
||||
databases from one place to another with minimal downtime.
|
||||
|
||||
```yaml
|
||||
standby_cluster:
|
||||
create_replica_methods:
|
||||
- bootstrap_standby_with_wale
|
||||
- basebackup_fast_xlog
|
||||
restore_command: envdir "/home/postgres/etc/wal-e.d/env-standby" /scripts/restore_command.sh
|
||||
"%f" "%p"
|
||||
```
|
||||
Before promoting a standby cluster, make sure that the standby is not behind
|
||||
the source database. You should ideally stop writes to your source cluster and
|
||||
then create a dummy database object that you check for being replicated in the
|
||||
target to verify all data has been copied.
|
||||
|
||||
Finally, remove the `standby` section from the postgres cluster manifest.
|
||||
To promote, remove the `standby` section from the postgres cluster manifest.
|
||||
A rolling update will be triggered removing the `STANDBY_*` environment
|
||||
variables from the pods, followed by a Patroni config update that promotes the
|
||||
cluster.
|
||||
|
||||
### Turn a normal cluster into a standby
|
||||
### Adding standby section after promotion
|
||||
|
||||
There is no way to transform a non-standby cluster to a standby cluster through
|
||||
the operator. Adding the `standby` section to the manifest of a running
|
||||
Postgres cluster will have no effect. But, as explained in the previous
|
||||
paragraph it can be done manually through `patronictl edit-config`. This time,
|
||||
by adding the `standby_cluster` section to the Patroni configuration. However,
|
||||
the transformed standby cluster will not be doing any streaming. It will be in
|
||||
standby mode and allow read-only transactions only.
|
||||
Turning a running cluster into a standby is not easily possible and should be
|
||||
avoided. The best way is to remove the cluster and resubmit the manifest
|
||||
after a short wait of a few minutes. Adding the `standby` section would turn
|
||||
the database cluster in read-only mode on next operator SYNC cycle but it
|
||||
does not sync automatically with the source cluster again.
|
||||
|
||||
## Sidecar Support
|
||||
|
||||
|
|
@ -845,6 +1030,7 @@ spec:
|
|||
env:
|
||||
- name: "ENV_VAR_NAME"
|
||||
value: "any-k8s-env-things"
|
||||
command: ['sh', '-c', 'echo "logging" > /opt/logs.txt']
|
||||
```
|
||||
|
||||
In addition to any environment variables you specify, the following environment
|
||||
|
|
@ -864,6 +1050,42 @@ option must be set to `true`.
|
|||
|
||||
If you want to add a sidecar to every cluster managed by the operator, you can specify it in the [operator configuration](administrator.md#sidecars-for-postgres-clusters) instead.
|
||||
|
||||
### Accessing the PostgreSQL socket from sidecars
|
||||
|
||||
If enabled by the `share_pgsocket_with_sidecars` option in the operator
|
||||
configuration the PostgreSQL socket is placed in a volume of type `emptyDir`
|
||||
named `postgresql-run`. To allow access to the socket from any sidecar
|
||||
container simply add a VolumeMount to this volume to your sidecar spec.
|
||||
|
||||
```yaml
|
||||
- name: "container-name"
|
||||
image: "company/image:tag"
|
||||
volumeMounts:
|
||||
- mountPath: /var/run
|
||||
name: postgresql-run
|
||||
```
|
||||
|
||||
If you do not want to globally enable this feature and only use it for single
|
||||
Postgres clusters, specify an `EmptyDir` volume under `additionalVolumes` in
|
||||
the manifest:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
additionalVolumes:
|
||||
- name: postgresql-run
|
||||
mountPath: /var/run/postgresql
|
||||
targetContainers:
|
||||
- all
|
||||
volumeSource:
|
||||
emptyDir: {}
|
||||
sidecars:
|
||||
- name: "container-name"
|
||||
image: "company/image:tag"
|
||||
volumeMounts:
|
||||
- mountPath: /var/run
|
||||
name: postgresql-run
|
||||
```
|
||||
|
||||
## InitContainers Support
|
||||
|
||||
Each cluster can specify arbitrary init containers to run. These containers can
|
||||
|
|
@ -888,9 +1110,9 @@ specified but globally disabled in the configuration. The
|
|||
|
||||
## Increase volume size
|
||||
|
||||
Postgres operator supports statefulset volume resize if you're using the
|
||||
operator on top of AWS. For that you need to change the size field of the
|
||||
volume description in the cluster manifest and apply the change:
|
||||
Postgres operator supports statefulset volume resize without doing a rolling
|
||||
update. For that you need to change the size field of the volume description
|
||||
in the cluster manifest and apply the change:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
|
|
@ -899,22 +1121,29 @@ spec:
|
|||
```
|
||||
|
||||
The operator compares the new value of the size field with the previous one and
|
||||
acts on differences.
|
||||
acts on differences. The `storage_resize_mode` can be configured. By default,
|
||||
the operator will adjust the PVCs and leave it to K8s and the infrastructure to
|
||||
apply the change.
|
||||
|
||||
You can only enlarge the volume with the process described above, shrinking is
|
||||
not supported and will emit a warning. After this update all the new volumes in
|
||||
the statefulset are allocated according to the new size. To enlarge persistent
|
||||
volumes attached to the running pods, the operator performs the following
|
||||
actions:
|
||||
When using AWS with gp3 volumes you should set the mode to `mixed` because it
|
||||
will also adjust the IOPS and throughput that can be defined in the manifest.
|
||||
Check the [AWS docs](https://aws.amazon.com/ebs/general-purpose/) to learn
|
||||
about default and maximum values. Keep in mind that AWS rate-limits updating
|
||||
volume specs to no more than once every 6 hours.
|
||||
|
||||
* call AWS API to change the volume size
|
||||
```yaml
|
||||
spec:
|
||||
volume:
|
||||
size: 5Gi # new volume size
|
||||
iops: 4000
|
||||
throughput: 500
|
||||
```
|
||||
|
||||
* connect to pod using `kubectl exec` and resize filesystem with `resize2fs`.
|
||||
|
||||
Fist step has a limitation, AWS rate-limits this operation to no more than once
|
||||
every 6 hours. Note, that if the statefulset is scaled down before resizing the
|
||||
new size is only applied to the volumes attached to the running pods. The
|
||||
size of volumes that correspond to the previously running pods is not changed.
|
||||
The operator can only enlarge volumes. Shrinking is not supported and will emit
|
||||
a warning. However, it can be done manually after updating the manifest. You
|
||||
have to delete the PVC, which will hang until you also delete the corresponding
|
||||
pod. Proceed with the next pod when the cluster is healthy again and replicas
|
||||
are streaming.
|
||||
|
||||
## Logical backups
|
||||
|
||||
|
|
@ -1012,14 +1241,19 @@ don't know the value, use `103` which is the GID from the default Spilo image
|
|||
OpenShift allocates the users and groups dynamically (based on scc), and their
|
||||
range is different in every namespace. Due to this dynamic behaviour, it's not
|
||||
trivial to know at deploy time the uid/gid of the user in the cluster.
|
||||
Therefore, instead of using a global `spilo_fsgroup` setting, use the
|
||||
`spiloFSGroup` field per Postgres cluster.
|
||||
Therefore, instead of using a global `spilo_fsgroup` setting in operator
|
||||
configuration or use the `spiloFSGroup` field per Postgres cluster manifest.
|
||||
|
||||
For testing purposes, you can generate a self-signed certificate with openssl:
|
||||
```sh
|
||||
openssl req -x509 -nodes -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=acid.zalan.do"
|
||||
```
|
||||
|
||||
Upload the cert as a kubernetes secret:
|
||||
```sh
|
||||
kubectl create secret tls pg-tls \
|
||||
--key pg-tls.key \
|
||||
--cert pg-tls.crt
|
||||
--key tls.key \
|
||||
--cert tls.crt
|
||||
```
|
||||
|
||||
When doing client auth, CA can come optionally from the same secret:
|
||||
|
|
@ -1046,8 +1280,7 @@ spec:
|
|||
|
||||
Optionally, the CA can be provided by a different secret:
|
||||
```sh
|
||||
kubectl create secret generic pg-tls-ca \
|
||||
--from-file=ca.crt=ca.crt
|
||||
kubectl create secret generic pg-tls-ca --from-file=ca.crt=ca.crt
|
||||
```
|
||||
|
||||
Then configure the postgres resource with the TLS secret:
|
||||
|
|
@ -1070,3 +1303,16 @@ Alternatively, it is also possible to use
|
|||
|
||||
Certificate rotation is handled in the Spilo image which checks every 5
|
||||
minutes if the certificates have changed and reloads postgres accordingly.
|
||||
|
||||
### TLS certificates for connection pooler
|
||||
|
||||
By default, the pgBouncer image generates its own TLS certificate like Spilo.
|
||||
When the `tls` section is specified in the manifest it will be used for the
|
||||
connection pooler pod(s) as well. The security context options are hard coded
|
||||
to `runAsUser: 100` and `runAsGroup: 101`. The `fsGroup` will be the same
|
||||
like for Spilo.
|
||||
|
||||
As of now, the operator does not sync the pooler deployment automatically
|
||||
which means that changes in the pod template are not caught. You need to
|
||||
toggle `enableConnectionPooler` to set environment variables, volumes, secret
|
||||
mounts and securityContext required for TLS support in the pooler pod.
|
||||
|
|
|
|||
|
|
@ -1,28 +1,20 @@
|
|||
# An image to run e2e tests.
|
||||
# The image does not include the tests; all necessary files are bind-mounted when a container starts.
|
||||
FROM ubuntu:20.04
|
||||
FROM python:3.11-slim
|
||||
LABEL maintainer="Team ACID @ Zalando <team-acid@zalando.de>"
|
||||
|
||||
ENV TERM xterm-256color
|
||||
|
||||
COPY requirements.txt ./
|
||||
COPY scm-source.json ./
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
python3-pip \
|
||||
curl \
|
||||
vim \
|
||||
&& pip3 install --no-cache-dir -r requirements.txt \
|
||||
&& curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl \
|
||||
RUN apt-get -qq -y update \
|
||||
# https://www.psycopg.org/docs/install.html#psycopg-vs-psycopg-binary
|
||||
&& apt-get -qq -y install --no-install-recommends curl vim python3-dev \
|
||||
&& curl -LO https://dl.k8s.io/release/v1.36.1/bin/linux/amd64/kubectl \
|
||||
&& chmod +x ./kubectl \
|
||||
&& mv ./kubectl /usr/local/bin/kubectl \
|
||||
&& apt-get clean \
|
||||
&& apt-get -qq -y clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# working line
|
||||
# python3 -m unittest discover -v --failfast -k test_e2e.EndToEndTestCase.test_lazy_spilo_upgrade --start-directory tests
|
||||
ENTRYPOINT ["python3", "-m", "unittest"]
|
||||
CMD ["discover","-v","--failfast","--start-directory","/tests"]
|
||||
COPY requirements.txt ./
|
||||
RUN pip install -r ./requirements.txt
|
||||
|
||||
CMD ["python", "-m", "unittest", "discover", "-v", "--failfast", "--start-directory", "/tests"]
|
||||
17
e2e/Makefile
17
e2e/Makefile
|
|
@ -11,7 +11,7 @@ endif
|
|||
LOCAL_BUILD_FLAGS ?= $(BUILD_FLAGS)
|
||||
LDFLAGS ?= -X=main.version=$(VERSION)
|
||||
|
||||
IMAGE ?= registry.opensource.zalan.do/acid/$(BINARY)
|
||||
IMAGE ?= ghcr.io/zalando/$(BINARY)
|
||||
VERSION ?= $(shell git describe --tags --always --dirty)
|
||||
TAG ?= $(VERSION)
|
||||
GITHEAD = $(shell git rev-parse --short HEAD)
|
||||
|
|
@ -29,25 +29,24 @@ default: tools
|
|||
|
||||
clean:
|
||||
rm -rf manifests
|
||||
rm -rf tls
|
||||
|
||||
copy: clean
|
||||
mkdir manifests
|
||||
cp ../manifests -r .
|
||||
cp -r ../manifests .
|
||||
mkdir tls
|
||||
|
||||
docker: scm-source.json
|
||||
docker:
|
||||
docker build -t "$(IMAGE):$(TAG)" .
|
||||
|
||||
scm-source.json: ../.git
|
||||
echo '{\n "url": "git:$(GITURL)",\n "revision": "$(GITHEAD)",\n "author": "$(USER)",\n "status": "$(GITSTATUS)"\n}' > scm-source.json
|
||||
|
||||
push: docker
|
||||
docker push "$(IMAGE):$(TAG)"
|
||||
|
||||
tools:
|
||||
# install pinned version of 'kind'
|
||||
# go get must run outside of a dir with a (module-based) Go project !
|
||||
# otherwise go get updates project's dependencies and/or behaves differently
|
||||
cd "/tmp" && GO111MODULE=on go get sigs.k8s.io/kind@v0.9.0
|
||||
# go install must run outside of a dir with a (module-based) Go project !
|
||||
# otherwise go install updates project's dependencies and/or behaves differently
|
||||
cd "/tmp" && go install sigs.k8s.io/kind@v0.27.0
|
||||
|
||||
e2etest: tools copy clean
|
||||
./run.sh main
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
export cluster_name="postgres-operator-e2e-tests"
|
||||
export kubeconfig_path="/tmp/kind-config-${cluster_name}"
|
||||
export operator_image="registry.opensource.zalan.do/acid/postgres-operator:latest"
|
||||
export e2e_test_runner_image="registry.opensource.zalan.do/acid/postgres-operator-e2e-tests-runner:0.3"
|
||||
export operator_image="ghcr.io/zalando/postgres-operator:latest"
|
||||
export pooler_image="ghcr.io/zalando/postgres-operator/pgbouncer:latest"
|
||||
export e2e_test_runner_image="ghcr.io/zalando/postgres-operator-e2e-tests-runner:latest"
|
||||
|
||||
docker run -it --entrypoint /bin/bash --network=host -e "TERM=xterm-256color" \
|
||||
--mount type=bind,source="$(readlink -f ${kubeconfig_path})",target=/root/.kube/config \
|
||||
|
|
@ -11,4 +12,5 @@ docker run -it --entrypoint /bin/bash --network=host -e "TERM=xterm-256color" \
|
|||
--mount type=bind,source="$(readlink -f tests)",target=/tests \
|
||||
--mount type=bind,source="$(readlink -f exec.sh)",target=/exec.sh \
|
||||
--mount type=bind,source="$(readlink -f scripts)",target=/scripts \
|
||||
-e OPERATOR_IMAGE="${operator_image}" "${e2e_test_runner_image}"
|
||||
-e OPERATOR_IMAGE="${operator_image}" -e POOLER_IMAGE="${pooler_image}" \
|
||||
"${e2e_test_runner_image}"
|
||||
|
|
|
|||
|
|
@ -4,3 +4,5 @@ nodes:
|
|||
- role: control-plane
|
||||
- role: worker
|
||||
- role: worker
|
||||
featureGates:
|
||||
StatefulSetAutoDeletePVC: true
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
kubernetes==11.0.0
|
||||
timeout_decorator==0.4.1
|
||||
pyyaml==5.4.1
|
||||
kubernetes==31.0.0
|
||||
timeout_decorator==0.5.0
|
||||
pyyaml==6.0.3
|
||||
|
|
|
|||
67
e2e/run.sh
67
e2e/run.sh
|
|
@ -7,23 +7,52 @@ set -o pipefail
|
|||
IFS=$'\n\t'
|
||||
|
||||
readonly cluster_name="postgres-operator-e2e-tests"
|
||||
readonly kubeconfig_path="/tmp/kind-config-${cluster_name}"
|
||||
readonly spilo_image="registry.opensource.zalan.do/acid/spilo-13-e2e:0.3"
|
||||
readonly e2e_test_runner_image="registry.opensource.zalan.do/acid/postgres-operator-e2e-tests-runner:0.3"
|
||||
readonly kubeconfig_path="${HOME}/kind-config-${cluster_name}"
|
||||
readonly spilo_image="ghcr.io/zalando/spilo-18:4.1-p1"
|
||||
readonly e2e_test_runner_image="ghcr.io/zalando/postgres-operator-e2e-tests-runner:latest"
|
||||
|
||||
export GOPATH=${GOPATH-~/go}
|
||||
export PATH=${GOPATH}/bin:$PATH
|
||||
|
||||
# detect system architecture for pulling the correct Spilo image
|
||||
case "$(uname -m)" in
|
||||
x86_64) readonly PLATFORM="linux/amd64" ;;
|
||||
aarch64|arm64) readonly PLATFORM="linux/arm64" ;;
|
||||
*) echo "Unsupported architecture: $(uname -m)"; exit 1 ;;
|
||||
esac
|
||||
|
||||
echo "Clustername: ${cluster_name}"
|
||||
echo "Kubeconfig path: ${kubeconfig_path}"
|
||||
|
||||
function pull_images(){
|
||||
operator_tag=$(git describe --tags --always --dirty)
|
||||
if [[ -z $(docker images -q registry.opensource.zalan.do/acid/postgres-operator:${operator_tag}) ]]
|
||||
then
|
||||
docker pull registry.opensource.zalan.do/acid/postgres-operator:latest
|
||||
fi
|
||||
operator_image=$(docker images --filter=reference="registry.opensource.zalan.do/acid/postgres-operator" --format "{{.Repository}}:{{.Tag}}" | head -1)
|
||||
components=("postgres-operator" "pooler")
|
||||
image_urls=("ghcr.io/zalando/postgres-operator:${operator_tag}" "ghcr.io/zalando/postgres-operator/pgbouncer:${operator_tag}")
|
||||
|
||||
for i in "${!components[@]}"; do
|
||||
component="${components[$i]}"
|
||||
image="${image_urls[$i]}"
|
||||
|
||||
if [[ -z $(docker images -q "$image") ]]; then
|
||||
echo "Pulling $component image: $image"
|
||||
if ! docker pull "$image"; then
|
||||
echo "Failed to pull $component image: $image"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "$component image already exists: $image"
|
||||
fi
|
||||
|
||||
# Set variables for later use
|
||||
if [[ "$component" == "postgres-operator" ]]; then
|
||||
operator_image="$image"
|
||||
elif [[ "$component" == "pooler" ]]; then
|
||||
pooler_image="$image"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Using operator image: $operator_image"
|
||||
echo "Using pooler image: $pooler_image"
|
||||
}
|
||||
|
||||
function start_kind(){
|
||||
|
|
@ -36,14 +65,17 @@ function start_kind(){
|
|||
|
||||
export KUBECONFIG="${kubeconfig_path}"
|
||||
kind create cluster --name ${cluster_name} --config kind-cluster-postgres-operator-e2e-tests.yaml
|
||||
docker pull "${spilo_image}"
|
||||
|
||||
echo "Pulling Spilo image for platform ${PLATFORM}"
|
||||
docker pull --platform ${PLATFORM} "${spilo_image}"
|
||||
kind load docker-image "${spilo_image}" --name ${cluster_name}
|
||||
}
|
||||
|
||||
function load_operator_image() {
|
||||
echo "Loading operator image"
|
||||
function load_operator_images() {
|
||||
echo "Loading operator images"
|
||||
export KUBECONFIG="${kubeconfig_path}"
|
||||
kind load docker-image "${operator_image}" --name ${cluster_name}
|
||||
kind load docker-image "${pooler_image}" --name ${cluster_name}
|
||||
}
|
||||
|
||||
function set_kind_api_server_ip(){
|
||||
|
|
@ -52,7 +84,11 @@ function set_kind_api_server_ip(){
|
|||
# but update the IP address of the API server to the one from the Docker 'bridge' network
|
||||
readonly local kind_api_server_port=6443 # well-known in the 'kind' codebase
|
||||
readonly local kind_api_server=$(docker inspect --format "{{ .NetworkSettings.Networks.kind.IPAddress }}:${kind_api_server_port}" "${cluster_name}"-control-plane)
|
||||
sed -i "s/server.*$/server: https:\/\/$kind_api_server/g" "${kubeconfig_path}"
|
||||
sed "s/server.*$/server: https:\/\/$kind_api_server/g" "${kubeconfig_path}" > "${kubeconfig_path}".tmp && mv "${kubeconfig_path}".tmp "${kubeconfig_path}"
|
||||
}
|
||||
|
||||
function generate_certificate(){
|
||||
openssl req -x509 -nodes -newkey rsa:2048 -keyout tls/tls.key -out tls/tls.crt -subj "/CN=acid.zalan.do"
|
||||
}
|
||||
|
||||
function run_tests(){
|
||||
|
|
@ -62,10 +98,12 @@ function run_tests(){
|
|||
docker run --rm --network=host -e "TERM=xterm-256color" \
|
||||
--mount type=bind,source="$(readlink -f ${kubeconfig_path})",target=/root/.kube/config \
|
||||
--mount type=bind,source="$(readlink -f manifests)",target=/manifests \
|
||||
--mount type=bind,source="$(readlink -f tls)",target=/tls \
|
||||
--mount type=bind,source="$(readlink -f tests)",target=/tests \
|
||||
--mount type=bind,source="$(readlink -f exec.sh)",target=/exec.sh \
|
||||
--mount type=bind,source="$(readlink -f scripts)",target=/scripts \
|
||||
-e OPERATOR_IMAGE="${operator_image}" "${e2e_test_runner_image}" ${E2E_TEST_CASE-} $@
|
||||
-e OPERATOR_IMAGE="${operator_image}" -e POOLER_IMAGE="${pooler_image}" \
|
||||
"${e2e_test_runner_image}" ${E2E_TEST_CASE-} $@
|
||||
}
|
||||
|
||||
function cleanup(){
|
||||
|
|
@ -80,8 +118,9 @@ function main(){
|
|||
[[ -z ${NOCLEANUP-} ]] && trap "cleanup" QUIT TERM EXIT
|
||||
pull_images
|
||||
[[ ! -f ${kubeconfig_path} ]] && start_kind
|
||||
load_operator_image
|
||||
load_operator_images
|
||||
set_kind_api_server_ip
|
||||
generate_certificate
|
||||
|
||||
shift
|
||||
run_tests $@
|
||||
|
|
|
|||
|
|
@ -20,12 +20,13 @@ class K8sApi:
|
|||
|
||||
self.config = config.load_kube_config()
|
||||
self.k8s_client = client.ApiClient()
|
||||
self.rbac_api = client.RbacAuthorizationV1Api()
|
||||
|
||||
self.core_v1 = client.CoreV1Api()
|
||||
self.apps_v1 = client.AppsV1Api()
|
||||
self.batch_v1_beta1 = client.BatchV1beta1Api()
|
||||
self.batch_v1 = client.BatchV1Api()
|
||||
self.custom_objects_api = client.CustomObjectsApi()
|
||||
self.policy_v1_beta1 = client.PolicyV1beta1Api()
|
||||
self.policy_v1 = client.PolicyV1Api()
|
||||
self.storage_v1_api = client.StorageV1Api()
|
||||
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ class K8s:
|
|||
|
||||
return master_pod_node, replica_pod_nodes
|
||||
|
||||
def get_cluster_nodes(self, cluster_labels='cluster-name=acid-minimal-cluster', namespace='default'):
|
||||
def get_cluster_nodes(self, cluster_labels='application=spilo,cluster-name=acid-minimal-cluster', namespace='default'):
|
||||
m = []
|
||||
r = []
|
||||
podsList = self.api.core_v1.list_namespaced_pod(namespace, label_selector=cluster_labels)
|
||||
|
|
@ -156,6 +157,30 @@ class K8s:
|
|||
while not get_services():
|
||||
time.sleep(self.RETRY_TIMEOUT_SEC)
|
||||
|
||||
def count_pods_with_volume_mount(self, mount_name, labels, namespace='default'):
|
||||
pod_count = 0
|
||||
pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items
|
||||
for pod in pods:
|
||||
for mount in pod.spec.containers[0].volume_mounts:
|
||||
if mount.name == mount_name:
|
||||
pod_count += 1
|
||||
|
||||
return pod_count
|
||||
|
||||
def count_pods_with_env_variable(self, env_variable_key, labels, namespace='default'):
|
||||
pod_count = 0
|
||||
pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items
|
||||
for pod in pods:
|
||||
for env in pod.spec.containers[0].env:
|
||||
if env.name == env_variable_key:
|
||||
pod_count += 1
|
||||
|
||||
return pod_count
|
||||
|
||||
def count_pods_with_rolling_update_flag(self, labels, namespace='default'):
|
||||
pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items
|
||||
return len(list(filter(lambda x: "zalando-postgres-operator-rolling-update-required" in x.metadata.annotations, pods)))
|
||||
|
||||
def count_pods_with_label(self, labels, namespace='default'):
|
||||
return len(self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items)
|
||||
|
||||
|
|
@ -175,9 +200,12 @@ class K8s:
|
|||
return len(self.api.apps_v1.list_namespaced_deployment(namespace, label_selector=labels).items)
|
||||
|
||||
def count_pdbs_with_label(self, labels, namespace='default'):
|
||||
return len(self.api.policy_v1_beta1.list_namespaced_pod_disruption_budget(
|
||||
return len(self.api.policy_v1.list_namespaced_pod_disruption_budget(
|
||||
namespace, label_selector=labels).items)
|
||||
|
||||
def count_pvcs_with_label(self, labels, namespace='default'):
|
||||
return len(self.api.core_v1.list_namespaced_persistent_volume_claim(namespace, label_selector=labels).items)
|
||||
|
||||
def count_running_pods(self, labels='application=spilo,cluster-name=acid-minimal-cluster', namespace='default'):
|
||||
pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items
|
||||
return len(list(filter(lambda x: x.status.phase == 'Running', pods)))
|
||||
|
|
@ -189,16 +217,30 @@ class K8s:
|
|||
def wait_for_pod_failover(self, failover_targets, labels, namespace='default'):
|
||||
pod_phase = 'Failing over'
|
||||
new_pod_node = ''
|
||||
|
||||
pods_with_update_flag = self.count_pods_with_rolling_update_flag(labels, namespace)
|
||||
while (pod_phase != 'Running') or (new_pod_node not in failover_targets):
|
||||
pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items
|
||||
if pods:
|
||||
new_pod_node = pods[0].spec.node_name
|
||||
pod_phase = pods[0].status.phase
|
||||
time.sleep(self.RETRY_TIMEOUT_SEC)
|
||||
|
||||
while pods_with_update_flag != 0:
|
||||
pods_with_update_flag = self.count_pods_with_rolling_update_flag(labels, namespace)
|
||||
time.sleep(self.RETRY_TIMEOUT_SEC)
|
||||
|
||||
def wait_for_namespace_creation(self, namespace='default'):
|
||||
ns_found = False
|
||||
while ns_found != True:
|
||||
ns = self.api.core_v1.list_namespace().items
|
||||
for n in ns:
|
||||
if n.metadata.name == namespace:
|
||||
ns_found = True
|
||||
break
|
||||
time.sleep(self.RETRY_TIMEOUT_SEC)
|
||||
|
||||
def get_logical_backup_job(self, namespace='default'):
|
||||
return self.api.batch_v1_beta1.list_namespaced_cron_job(namespace, label_selector="application=spilo")
|
||||
return self.api.batch_v1.list_namespaced_cron_job(namespace, label_selector="application=spilo-logical-backup")
|
||||
|
||||
def wait_for_logical_backup_job(self, expected_num_of_jobs):
|
||||
while (len(self.get_logical_backup_job().items) != expected_num_of_jobs):
|
||||
|
|
@ -222,6 +264,18 @@ class K8s:
|
|||
def patch_pod(self, data, pod_name, namespace="default"):
|
||||
self.api.core_v1.patch_namespaced_pod(pod_name, namespace, data)
|
||||
|
||||
def create_tls_secret_with_kubectl(self, secret_name):
|
||||
return subprocess.run(
|
||||
["kubectl", "create", "secret", "tls", secret_name, "--key=tls/tls.key", "--cert=tls/tls.crt"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
def create_tls_ca_secret_with_kubectl(self, secret_name):
|
||||
return subprocess.run(
|
||||
["kubectl", "create", "secret", "generic", secret_name, "--from-file=ca.crt=tls/ca.crt"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
def create_with_kubectl(self, path):
|
||||
return subprocess.run(
|
||||
["kubectl", "apply", "-f", path],
|
||||
|
|
@ -233,6 +287,13 @@ class K8s:
|
|||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
def patroni_rest(self, pod, path):
|
||||
r = self.exec_with_kubectl(pod, "curl localhost:8008/" + path)
|
||||
if not r.returncode == 0 or not r.stdout.decode()[0:1] == "{":
|
||||
return None
|
||||
|
||||
return json.loads(r.stdout.decode())
|
||||
|
||||
def get_patroni_state(self, pod):
|
||||
r = self.exec_with_kubectl(pod, "patronictl list -f json")
|
||||
if not r.returncode == 0 or not r.stdout.decode()[0:1] == "[":
|
||||
|
|
@ -253,7 +314,7 @@ class K8s:
|
|||
|
||||
def get_patroni_running_members(self, pod="acid-minimal-cluster-0"):
|
||||
result = self.get_patroni_state(pod)
|
||||
return list(filter(lambda x: "State" in x and x["State"] == "running", result))
|
||||
return list(filter(lambda x: "State" in x and x["State"] in ["running", "streaming"], result))
|
||||
|
||||
def get_deployment_replica_count(self, name="acid-minimal-cluster-pooler", namespace="default"):
|
||||
try:
|
||||
|
|
@ -295,6 +356,15 @@ class K8s:
|
|||
def get_cluster_replica_pod(self, labels='application=spilo,cluster-name=acid-minimal-cluster', namespace='default'):
|
||||
return self.get_cluster_pod('replica', labels, namespace)
|
||||
|
||||
def get_secret(self, username, clustername='acid-minimal-cluster', namespace='default'):
|
||||
secret = self.api.core_v1.read_namespaced_secret(
|
||||
"{}.{}.credentials.postgresql.acid.zalan.do".format(username.replace("_","-"), clustername), namespace)
|
||||
secret.metadata.resource_version = None
|
||||
secret.metadata.uid = None
|
||||
return secret
|
||||
|
||||
def create_secret(self, secret, namespace='default'):
|
||||
return self.api.core_v1.create_namespaced_secret(namespace, secret)
|
||||
|
||||
class K8sBase:
|
||||
'''
|
||||
|
|
@ -413,6 +483,10 @@ class K8sBase:
|
|||
while not get_services():
|
||||
time.sleep(self.RETRY_TIMEOUT_SEC)
|
||||
|
||||
def count_pods_with_rolling_update_flag(self, labels, namespace='default'):
|
||||
pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items
|
||||
return len(list(filter(lambda x: "zalando-postgres-operator-rolling-update-required" in x.metadata.annotations, pods)))
|
||||
|
||||
def count_pods_with_label(self, labels, namespace='default'):
|
||||
return len(self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items)
|
||||
|
||||
|
|
@ -432,9 +506,12 @@ class K8sBase:
|
|||
return len(self.api.apps_v1.list_namespaced_deployment(namespace, label_selector=labels).items)
|
||||
|
||||
def count_pdbs_with_label(self, labels, namespace='default'):
|
||||
return len(self.api.policy_v1_beta1.list_namespaced_pod_disruption_budget(
|
||||
return len(self.api.policy_v1.list_namespaced_pod_disruption_budget(
|
||||
namespace, label_selector=labels).items)
|
||||
|
||||
def count_pvcs_with_label(self, labels, namespace='default'):
|
||||
return len(self.api.core_v1.list_namespaced_persistent_volume_claim(namespace, label_selector=labels).items)
|
||||
|
||||
def count_running_pods(self, labels='application=spilo,cluster-name=acid-minimal-cluster', namespace='default'):
|
||||
pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items
|
||||
return len(list(filter(lambda x: x.status.phase == 'Running', pods)))
|
||||
|
|
@ -446,7 +523,7 @@ class K8sBase:
|
|||
def wait_for_pod_failover(self, failover_targets, labels, namespace='default'):
|
||||
pod_phase = 'Failing over'
|
||||
new_pod_node = ''
|
||||
|
||||
pods_with_update_flag = self.count_pods_with_rolling_update_flag(labels, namespace)
|
||||
while (pod_phase != 'Running') or (new_pod_node not in failover_targets):
|
||||
pods = self.api.core_v1.list_namespaced_pod(namespace, label_selector=labels).items
|
||||
if pods:
|
||||
|
|
@ -454,8 +531,12 @@ class K8sBase:
|
|||
pod_phase = pods[0].status.phase
|
||||
time.sleep(self.RETRY_TIMEOUT_SEC)
|
||||
|
||||
while pods_with_update_flag != 0:
|
||||
pods_with_update_flag = self.count_pods_with_rolling_update_flag(labels, namespace)
|
||||
time.sleep(self.RETRY_TIMEOUT_SEC)
|
||||
|
||||
def get_logical_backup_job(self, namespace='default'):
|
||||
return self.api.batch_v1_beta1.list_namespaced_cron_job(namespace, label_selector="application=spilo")
|
||||
return self.api.batch_v1.list_namespaced_cron_job(namespace, label_selector="application=spilo")
|
||||
|
||||
def wait_for_logical_backup_job(self, expected_num_of_jobs):
|
||||
while (len(self.get_logical_backup_job().items) != expected_num_of_jobs):
|
||||
|
|
@ -486,6 +567,13 @@ class K8sBase:
|
|||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
def patroni_rest(self, pod, path):
|
||||
r = self.exec_with_kubectl(pod, "curl localhost:8008/" + path)
|
||||
if not r.returncode == 0 or not r.stdout.decode()[0:1] == "{":
|
||||
return None
|
||||
|
||||
return json.loads(r.stdout.decode())
|
||||
|
||||
def get_patroni_state(self, pod):
|
||||
r = self.exec_with_kubectl(pod, "patronictl list -f json")
|
||||
if not r.returncode == 0 or not r.stdout.decode()[0:1] == "[":
|
||||
|
|
@ -494,7 +582,7 @@ class K8sBase:
|
|||
|
||||
def get_patroni_running_members(self, pod):
|
||||
result = self.get_patroni_state(pod)
|
||||
return list(filter(lambda x: x["State"] == "running", result))
|
||||
return list(filter(lambda x: x["State"] in ["running", "streaming"], result))
|
||||
|
||||
def get_statefulset_image(self, label_selector="application=spilo,cluster-name=acid-minimal-cluster", namespace='default'):
|
||||
ssets = self.api.apps_v1.list_namespaced_stateful_set(namespace, label_selector=label_selector, limit=1)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
108
go.mod
108
go.mod
|
|
@ -1,21 +1,101 @@
|
|||
module github.com/zalando/postgres-operator
|
||||
|
||||
go 1.15
|
||||
go 1.26.4
|
||||
|
||||
require (
|
||||
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/Masterminds/semver/v3 v3.5.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.42.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.24
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.305.3
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/lib/pq v1.12.3
|
||||
github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/r3labs/diff v1.1.0
|
||||
github.com/sirupsen/logrus v1.7.0
|
||||
github.com/stretchr/testify v1.6.1
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
|
||||
golang.org/x/mod v0.4.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.20.6
|
||||
k8s.io/apiextensions-apiserver v0.20.6
|
||||
k8s.io/apimachinery v0.20.6
|
||||
k8s.io/client-go v0.20.6
|
||||
k8s.io/code-generator v0.20.6
|
||||
github.com/sirupsen/logrus v1.9.4
|
||||
github.com/stretchr/testify v1.11.1
|
||||
golang.org/x/crypto v0.51.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.36.1
|
||||
k8s.io/apiextensions-apiserver v0.36.1
|
||||
k8s.io/apimachinery v0.36.1
|
||||
k8s.io/client-go v0.36.1
|
||||
sigs.k8s.io/yaml v1.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.23 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.1.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 // indirect
|
||||
github.com/aws/smithy-go v1.27.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/gobuffalo/flect v1.0.3 // indirect
|
||||
github.com/google/gnostic-models v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/moby/spdystream v0.5.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/spf13/cobra v1.10.2 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/mod v0.36.0 // indirect
|
||||
golang.org/x/net v0.55.0 // indirect
|
||||
golang.org/x/oauth2 v0.34.0 // indirect
|
||||
golang.org/x/sync v0.21.0 // indirect
|
||||
golang.org/x/sys v0.46.0 // indirect
|
||||
golang.org/x/term v0.44.0 // indirect
|
||||
golang.org/x/text v0.38.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/tools v0.45.0 // indirect
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/code-generator v0.36.1 // indirect
|
||||
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect
|
||||
k8s.io/klog/v2 v2.140.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
|
||||
k8s.io/streaming v0.36.1 // indirect
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
|
||||
sigs.k8s.io/controller-tools v0.17.3 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
|
||||
)
|
||||
|
||||
tool (
|
||||
github.com/golang/mock/mockgen
|
||||
k8s.io/code-generator
|
||||
k8s.io/code-generator/cmd/client-gen
|
||||
k8s.io/code-generator/cmd/deepcopy-gen
|
||||
k8s.io/code-generator/cmd/informer-gen
|
||||
k8s.io/code-generator/cmd/lister-gen
|
||||
sigs.k8s.io/controller-tools/cmd/controller-gen
|
||||
)
|
||||
|
|
|
|||
836
go.sum
836
go.sum
|
|
@ -1,677 +1,243 @@
|
|||
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.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 v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
|
||||
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.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||
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.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||
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=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
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/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/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
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-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
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/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.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/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.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
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/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE=
|
||||
github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go-v2 v1.42.0 h1:XvXMJTkFQtpBKIWZnmr9ZEOc2InWM2yldjXEJ/bymhA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.42.0/go.mod h1:27+ACypSLljLAEKsCYOmrjKh83vuTRkuAe9Uv/3A4bg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.24 h1:aEDEj533yGdVvEHfkCY0D/1FbDrjnZr4pIulxRjqpHs=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.24/go.mod h1:yZtrGKJGlqfEW+/m2uTsJK+Jz7xF5R0eZfgcIG9m1ss=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.23 h1:Zhu3GOpRCkNjtE/gJpuPDsytSnaCCTQk8neAGsgzG5Y=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.23/go.mod h1:VsJF2ropPB37gDr7M2rLSpCE8IQWdpl62uae7qxZmqU=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29 h1:r6qZHbT+wxgWO/e9vYNUEtg7lv5+UN3pRqKhLXvnArg=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.29/go.mod h1:QRnaRcTVGKPGRy8w78HMQtKUGRYcnMZAANATkeVA6Mo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29 h1:f3vKqSo13fhTYb+JEcXwXefZQE26I1FB5eTSniU67ko=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.29/go.mod h1:MzoLFUArKGpGD+ukmPiTPG1X5x4o6M2kq4v2dr1FiEc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29 h1:RdwIf/CuUsvJX3RgJagbOyotl/cxoLY4xviKuE7p2GY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.29/go.mod h1:71wt8W2EgswdZy9Mf9KNnzxZ3TiZlv4caKghPktDOkA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30 h1:VTGy885W5DKBxWRUJbym9hytNaYzsyaPkCHGRRMAOhU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.30/go.mod h1:AS0HycUvJRFvTt613AYDOgO2jzw+00cVSMny8XB3yMY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.305.3 h1:rEay0b3E0qqyY+W0c3ox8wGRsVK+GjxXadj9B9vpg4c=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.305.3/go.mod h1:8mrDF7OtbuL0QpwP4YCvLuoOE4/5lL7D33MXgp069/Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12 h1:ZD2+BSw9vFsNlKYIasSNt3uDbjqqXIBcM13UJv/Lx2k=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.12/go.mod h1:Ms4zlcVBbXbiP7EVLhl+lgjvA/a7YphqQ3Ih3174EmI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29 h1:DRebniUGZ2MqiiIVmQJ04vIXr918hubdHMnarSLEWyU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.29/go.mod h1:LfRkPCD8YHDM2E5eTkos2UpwYeZnBcVarTa8L59bJHA=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.1.5 h1:6Xt6Ztjkwdia/7EtEaG7ki/qZUYlCcd7tGUotQed1QE=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.1.5/go.mod h1:LxYujSTLPRlp2vTtcUO/+1ilrew8ytt6SvQyOgejzFQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.31.3 h1:ey1XLTYXb9PcLt4535632o5kCGXNXEhNb620Dqwuylo=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.31.3/go.mod h1:Lk7PlmoTYryQmyBG0EXqj5BcUbj3whXdU2s3yGI3EAc=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6 h1:yLr03zQE/5Eu5l3QU0Si+xMbLMbSDF2YXsigqXngs6g=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.6/go.mod h1:Q5N6icH+KJZDLh+ESNwzdv6cZ6vLFF/egy3IOxWhmz4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3 h1:VrIhKRCSK1umelSgB9RghvA9RTUYeQffyAS5ApXehNI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.43.3/go.mod h1:r8wkDOuLaaMFqFiYAb8dGY2A3gJCOujMc6CFOVC4Zhc=
|
||||
github.com/aws/smithy-go v1.27.1 h1:4T340VFndXtADGF52gYa1POyL7s9E4Z1OeZ1hCscIw8=
|
||||
github.com/aws/smithy-go v1.27.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
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 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/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/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 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||
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 h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
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 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=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/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/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
|
||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
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 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=
|
||||
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/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 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4=
|
||||
github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
||||
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
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/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=
|
||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
||||
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.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-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.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 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/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 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
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 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.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
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 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
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/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.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/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
|
||||
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y=
|
||||
github.com/moby/spdystream v0.5.1/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
|
||||
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-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/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
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 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
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.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
|
||||
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 v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
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/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/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.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.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-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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/r3labs/diff v1.1.0 h1:V53xhrbTHrWFWq3gI4b94AjgEJOerO1+1l0xyHOBi8M=
|
||||
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/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/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/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
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=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
||||
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/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
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 v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
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 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
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/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
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.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
|
||||
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 v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
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/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
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/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=
|
||||
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-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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
|
||||
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
|
||||
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
|
||||
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-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-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-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/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
||||
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
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-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-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/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-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/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||
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/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/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-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=
|
||||
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-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
|
||||
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
|
||||
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
|
||||
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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
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/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
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/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.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=
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
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/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 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/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 h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
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=
|
||||
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.20.6 h1:bgdZrW++LqgrLikWYNruIKAtltXbSCX2l5mJu11hrVE=
|
||||
k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
|
||||
k8s.io/apiextensions-apiserver v0.20.6 h1:3ZJiXMif7W/32RnfyHN8HygTAZaN7o+FvHxCyuQ7VOo=
|
||||
k8s.io/apiextensions-apiserver v0.20.6/go.mod h1:qO8YMqeMmZH+lV21LUNzV41vfpoE9QVAJRA+MNqj0mo=
|
||||
k8s.io/apimachinery v0.20.6 h1:R5p3SlhaABYShQSO6LpPsYHjV05Q+79eBUR0Ut/f4tk=
|
||||
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
|
||||
k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
|
||||
k8s.io/client-go v0.20.6 h1:nJZOfolnsVtDtbGJNCxzOtKUAu7zvXjB8+pMo9UNxZo=
|
||||
k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
|
||||
k8s.io/code-generator v0.20.6 h1:kp65Y6kF6A4+5PvSNvXWSI5p5vuA9tUxEqEZciPw+7Q=
|
||||
k8s.io/code-generator v0.20.6/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU=
|
||||
k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
|
||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20201113003025-83324d819ded h1:JApXBKYyB7l9xx+DK7/+mFjC7A9Bt5A93FPvFD0HIFE=
|
||||
k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
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-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c=
|
||||
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
|
||||
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.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.3 h1:4oyYo8NREp49LBBhKxEqCulFjg26rawYKrnCmg+Sr6c=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/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=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.36.1 h1:XbL/EMj8K2aJpJtePmqUyQMsM0D4QI2pvl7YKJ20FTY=
|
||||
k8s.io/api v0.36.1/go.mod h1:KOWo4ey3TINlXjeHVuwB3i+tXXnu+UcwFBHlI/9dvEo=
|
||||
k8s.io/apiextensions-apiserver v0.36.1 h1:6JfYmPUsuUIHuN+3QxutXYWj492RqF5fBSx67GYK5Ks=
|
||||
k8s.io/apiextensions-apiserver v0.36.1/go.mod h1:pLzZin90riwisdzKwv/GoTwENooytoIx5zWJb4Hkby8=
|
||||
k8s.io/apimachinery v0.36.1 h1:G63Gjx2W+q0YD+72Vo8oY0nDnePVwnuzTmmy5ENrVSA=
|
||||
k8s.io/apimachinery v0.36.1/go.mod h1:ibYOR00vW/I1kzvi5SF0dRuJ52BvKtfvRdOn35GPQ+8=
|
||||
k8s.io/client-go v0.36.1 h1:FN/K8QIT2CEDt+2WB2HnWrUANZ50AP5GII43/SP2JR0=
|
||||
k8s.io/client-go v0.36.1/go.mod h1:s6rAnCtTGYDQnpNjEhSaISV+2O8jwruZ6m3QOYBFbtU=
|
||||
k8s.io/code-generator v0.36.1 h1:5bHQ7NbBcFFLHcoyo/hgU3m2tQV5RLz2nv4QNDlsbXc=
|
||||
k8s.io/code-generator v0.36.1/go.mod h1:oCv8WmrW2RGdcMyvSk1aYbBfSs51ggtSFQr1YNeuAuo=
|
||||
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ=
|
||||
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM=
|
||||
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
|
||||
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg=
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
|
||||
k8s.io/streaming v0.36.1 h1:L+K68n4Gg940BGNNYtUBvL1WTLL0YnKT3s+P1MNAmR4=
|
||||
k8s.io/streaming v0.36.1/go.mod h1:z6fV3D+NVkoeqRMtWwlUZK6U17SY/LqNzOxWL6GyR/s=
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
|
||||
sigs.k8s.io/controller-tools v0.17.3 h1:lwFPLicpBKLgIepah+c8ikRBubFW5kOQyT88r3EwfNw=
|
||||
sigs.k8s.io/controller-tools v0.17.3/go.mod h1:1ii+oXcYZkxcBXzwv3YZBlzjt1fvkrCGjVF73blosJI=
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Hack to adjust the generated postgresql CRD YAML file and add missing field
|
||||
# settings which can not be expressed via kubebuilder markers.
|
||||
#
|
||||
# Injections:
|
||||
#
|
||||
# * oneOf: for the standby field to enforce validation rules:
|
||||
# - s3_wal_path and gs_wal_path are mutually exclusive
|
||||
# - standby_host can be specified alone or with either s3_wal_path OR gs_wal_path
|
||||
# - at least one of s3_wal_path, gs_wal_path, or standby_host must be set
|
||||
# * type: string and pattern for the maintenanceWindows items.
|
||||
|
||||
file="${1:-"manifests/postgresql.crd.yaml"}"
|
||||
|
||||
sed -i '/^[[:space:]]*standby:$/{
|
||||
# Capture the indentation
|
||||
s/^\([[:space:]]*\)standby:$/\1standby:\n\1 anyOf:\n\1 - required:\n\1 - s3_wal_path\n\1 - required:\n\1 - gs_wal_path\n\1 - required:\n\1 - standby_host\n\1 not:\n\1 required:\n\1 - s3_wal_path\n\1 - gs_wal_path/
|
||||
}' "$file"
|
||||
|
||||
sed -i '/^[[:space:]]*maintenanceWindows:$/{
|
||||
# Capture the indentation
|
||||
s/^\([[:space:]]*\)maintenanceWindows:$/\1maintenanceWindows:\n\1 items:\n\1 pattern: '\''^\\ *((Mon|Tue|Wed|Thu|Fri|Sat|Sun):(2[0-3]|[01]?\\d):([0-5]?\\d)|(2[0-3]|[01]?\\d):([0-5]?\\d))-((2[0-3]|[01]?\\d):([0-5]?\\d)|(2[0-3]|[01]?\\d):([0-5]?\\d))\\ *$'\''\n\1 type: string/
|
||||
}' "$file"
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// +build tools
|
||||
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This package imports things required by build scripts, to force `go mod` to see them as dependencies
|
||||
package tools
|
||||
|
||||
import _ "k8s.io/code-generator"
|
||||
|
|
@ -1,13 +1,66 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2017 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/..
|
||||
CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ${GOPATH}/src/k8s.io/code-generator)}
|
||||
SRC="github.com"
|
||||
GOPKG="$SRC/zalando/postgres-operator"
|
||||
CUSTOM_RESOURCE_NAME_ZAL="zalando.org"
|
||||
CUSTOM_RESOURCE_NAME_ACID="acid.zalan.do"
|
||||
CUSTOM_RESOURCE_VERSION="v1"
|
||||
|
||||
bash "${CODEGEN_PKG}/generate-groups.sh" all \
|
||||
github.com/zalando/postgres-operator/pkg/generated github.com/zalando/postgres-operator/pkg/apis \
|
||||
"acid.zalan.do:v1" \
|
||||
--go-header-file "${SCRIPT_ROOT}"/hack/custom-boilerplate.go.txt
|
||||
SCRIPT_ROOT="$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
|
||||
OUTPUT_DIR="pkg/generated"
|
||||
OUTPUT_PKG="${GOPKG}/${OUTPUT_DIR}"
|
||||
APIS_PKG="${GOPKG}/pkg/apis"
|
||||
GROUPS_WITH_VERSIONS="${CUSTOM_RESOURCE_NAME_ZAL}:${CUSTOM_RESOURCE_VERSION},${CUSTOM_RESOURCE_NAME_ACID}:${CUSTOM_RESOURCE_VERSION}"
|
||||
|
||||
echo "Generating deepcopy funcs"
|
||||
go tool deepcopy-gen \
|
||||
--output-file zz_generated.deepcopy.go \
|
||||
--go-header-file "${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt" \
|
||||
"${APIS_PKG}/${CUSTOM_RESOURCE_NAME_ZAL}/${CUSTOM_RESOURCE_VERSION}" \
|
||||
"${APIS_PKG}/${CUSTOM_RESOURCE_NAME_ACID}/${CUSTOM_RESOURCE_VERSION}"
|
||||
|
||||
echo "Generating clientset for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}"
|
||||
go tool client-gen \
|
||||
--clientset-name versioned \
|
||||
--input-base "${APIS_PKG}" \
|
||||
--input "${CUSTOM_RESOURCE_NAME_ZAL}/${CUSTOM_RESOURCE_VERSION},${CUSTOM_RESOURCE_NAME_ACID}/${CUSTOM_RESOURCE_VERSION}" \
|
||||
--output-pkg "${OUTPUT_PKG}/clientset" \
|
||||
--go-header-file "${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt" \
|
||||
--output-dir "${OUTPUT_DIR}/clientset"
|
||||
|
||||
echo "Generating listers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/listers"
|
||||
go tool lister-gen \
|
||||
--output-pkg "${OUTPUT_PKG}/listers" \
|
||||
--go-header-file "${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt" \
|
||||
--output-dir "${OUTPUT_DIR}/listers" \
|
||||
"${APIS_PKG}/${CUSTOM_RESOURCE_NAME_ZAL}/${CUSTOM_RESOURCE_VERSION}" \
|
||||
"${APIS_PKG}/${CUSTOM_RESOURCE_NAME_ACID}/${CUSTOM_RESOURCE_VERSION}"
|
||||
|
||||
echo "Generating informers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/informers"
|
||||
go tool informer-gen \
|
||||
--versioned-clientset-package "${OUTPUT_PKG}/${CLIENTSET_PKG_NAME:-clientset}/${CLIENTSET_NAME_VERSIONED:-versioned}" \
|
||||
--listers-package "${OUTPUT_PKG}/listers" \
|
||||
--output-pkg "${OUTPUT_PKG}/informers" \
|
||||
--go-header-file "${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt" \
|
||||
--output-dir "${OUTPUT_DIR}/informers" \
|
||||
"${APIS_PKG}/${CUSTOM_RESOURCE_NAME_ZAL}/${CUSTOM_RESOURCE_VERSION}" \
|
||||
"${APIS_PKG}/${CUSTOM_RESOURCE_NAME_ACID}/${CUSTOM_RESOURCE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -19,15 +19,14 @@ cleanup
|
|||
mkdir -p "${TMP_DIFFROOT}"
|
||||
cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
|
||||
|
||||
"${SCRIPT_ROOT}/hack/update-codegen.sh"
|
||||
"${SCRIPT_ROOT}/hack/update-codegen.sh" "${TMP_DIFFROOT}"
|
||||
echo "diffing ${DIFFROOT} against freshly generated codegen"
|
||||
ret=0
|
||||
diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
|
||||
cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}"
|
||||
if [[ $ret -eq 0 ]]
|
||||
then
|
||||
echo "${DIFFROOT} up to date."
|
||||
else
|
||||
echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
|
||||
echo "${DIFFROOT} is out of date. Please run 'make codegen'"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,137 +0,0 @@
|
|||
# Kubectl Plugin for Zalando's Postgres Operator
|
||||
|
||||
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.
|
||||
|
||||
## 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
|
||||
|
||||
[kubectl pg proposal](https://docs.google.com/document/d/1-WMy9HkfZ1XnnMbzplMe9rCzKrRMGaMz4owLVXXPb7w/edit)
|
||||
|
||||
### Weekly Reports
|
||||
|
||||
https://github.com/VineethReddy02/GSoC-Kubectl-Plugin-for-Postgres-Operator-tracker
|
||||
|
||||
### Final Project Report
|
||||
|
||||
https://gist.github.com/VineethReddy02/159283bd368a710379eaf0f6bd60a40a
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
VERSION=1.0
|
||||
sed -i "s/KubectlPgVersion string = \"[^\"]*\"/KubectlPgVersion string = \"${VERSION}\"/" cmd/version.go
|
||||
go install
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
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"
|
||||
)
|
||||
|
||||
// addDbCmd represents the addDb command
|
||||
var addDbCmd = &cobra.Command{
|
||||
Use: "add-db",
|
||||
Short: "Adds a DB and its owner to a Postgres cluster. The owner role is created if it does not exist",
|
||||
Long: `Adds a new DB to the Postgres cluster. Owner needs to be specified by the -o flag, cluster with -c flag.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) > 0 {
|
||||
dbName := args[0]
|
||||
dbOwner, _ := cmd.Flags().GetString("owner")
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
addDb(dbName, dbOwner, clusterName)
|
||||
} else {
|
||||
fmt.Println("database name can't be empty. Use kubectl pg add-db [-h | --help] for more info")
|
||||
}
|
||||
|
||||
},
|
||||
Example: `
|
||||
kubectl pg add-db db01 -o owner01 -c cluster01
|
||||
`,
|
||||
}
|
||||
|
||||
// add db and it's owner to the cluster
|
||||
func addDb(dbName string, dbOwner string, clusterName string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
namespace := getCurrentNamespace()
|
||||
postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var dbOwnerExists bool
|
||||
dbUsers := postgresql.Spec.Users
|
||||
for key := range dbUsers {
|
||||
if key == dbOwner {
|
||||
dbOwnerExists = true
|
||||
}
|
||||
}
|
||||
var patch []byte
|
||||
// validating reserved DB names
|
||||
if dbOwnerExists && dbName != "postgres" && dbName != "template0" && dbName != "template1" {
|
||||
patch = dbPatch(dbName, dbOwner)
|
||||
} else if !dbOwnerExists {
|
||||
log.Fatal("The provided db-owner doesn't exist")
|
||||
} else {
|
||||
log.Fatal("The provided db-name is reserved by postgres")
|
||||
}
|
||||
|
||||
updatedPostgres, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if updatedPostgres.ResourceVersion != postgresql.ResourceVersion {
|
||||
fmt.Printf("Created new database %s with owner %s in PostgreSQL cluster %s.\n", dbName, dbOwner, updatedPostgres.Name)
|
||||
} else {
|
||||
fmt.Printf("postgresql %s is unchanged.\n", updatedPostgres.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func dbPatch(dbname string, owner string) []byte {
|
||||
ins := map[string]map[string]map[string]string{"spec": {"databases": {dbname: owner}}}
|
||||
patchInstances, err := json.Marshal(ins)
|
||||
if err != nil {
|
||||
log.Fatal(err, "unable to parse patch for add-db")
|
||||
}
|
||||
return patchInstances
|
||||
}
|
||||
|
||||
func init() {
|
||||
addDbCmd.Flags().StringP("owner", "o", "", "provide owner of the database.")
|
||||
addDbCmd.Flags().StringP("cluster", "c", "", "provide a postgres cluster name.")
|
||||
rootCmd.AddCommand(addDbCmd)
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
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"
|
||||
)
|
||||
|
||||
var allowedPrivileges = []string{"SUPERUSER", "REPLICATION", "INHERIT", "LOGIN", "NOLOGIN", "CREATEROLE", "CREATEDB", "BYPASSURL"}
|
||||
|
||||
// addUserCmd represents the addUser command
|
||||
var addUserCmd = &cobra.Command{
|
||||
Use: "add-user",
|
||||
Short: "Adds a user to the postgres cluster with given privileges",
|
||||
Long: `Adds a user to the postgres cluster. You can add privileges as well with -p flag.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
privileges, _ := cmd.Flags().GetString("privileges")
|
||||
|
||||
if len(args) > 0 {
|
||||
user := args[0]
|
||||
var permissions []string
|
||||
var perms []string
|
||||
|
||||
if privileges != "" {
|
||||
parsedRoles := strings.Replace(privileges, ",", " ", -1)
|
||||
parsedRoles = strings.ToUpper(parsedRoles)
|
||||
permissions = strings.Fields(parsedRoles)
|
||||
var invalidPerms []string
|
||||
|
||||
for _, userPrivilege := range permissions {
|
||||
validPerm := false
|
||||
for _, privilege := range allowedPrivileges {
|
||||
if privilege == userPrivilege {
|
||||
perms = append(perms, userPrivilege)
|
||||
validPerm = true
|
||||
}
|
||||
}
|
||||
if !validPerm {
|
||||
invalidPerms = append(invalidPerms, userPrivilege)
|
||||
}
|
||||
}
|
||||
|
||||
if len(invalidPerms) > 0 {
|
||||
fmt.Printf("Invalid privileges %s\n", invalidPerms)
|
||||
return
|
||||
}
|
||||
}
|
||||
addUser(user, clusterName, perms)
|
||||
}
|
||||
},
|
||||
Example: `
|
||||
kubectl pg add-user user01 -p login,createdb -c cluster01
|
||||
`,
|
||||
}
|
||||
|
||||
// add user to the cluster with provided permissions
|
||||
func addUser(user string, clusterName string, permissions []string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
namespace := getCurrentNamespace()
|
||||
postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
setUsers := make(map[string]bool)
|
||||
for _, k := range permissions {
|
||||
setUsers[k] = true
|
||||
}
|
||||
|
||||
if existingRoles, key := postgresql.Spec.Users[user]; key {
|
||||
for _, k := range existingRoles {
|
||||
setUsers[k] = true
|
||||
}
|
||||
}
|
||||
|
||||
Privileges := []string{}
|
||||
for keys, values := range setUsers {
|
||||
if values {
|
||||
Privileges = append(Privileges, keys)
|
||||
}
|
||||
}
|
||||
|
||||
patch := applyUserPatch(user, Privileges)
|
||||
updatedPostgresql, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if updatedPostgresql.ResourceVersion != postgresql.ResourceVersion {
|
||||
fmt.Printf("postgresql %s is updated with new user %s and with privileges %s.\n", updatedPostgresql.Name, user, permissions)
|
||||
} else {
|
||||
fmt.Printf("postgresql %s is unchanged.\n", updatedPostgresql.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func applyUserPatch(user string, value []string) []byte {
|
||||
ins := map[string]map[string]map[string][]string{"spec": {"users": {user: value}}}
|
||||
patchInstances, err := json.Marshal(ins)
|
||||
if err != nil {
|
||||
log.Fatal(err, "unable to parse number of instances json")
|
||||
}
|
||||
return patchInstances
|
||||
}
|
||||
|
||||
func init() {
|
||||
addUserCmd.Flags().StringP("cluster", "c", "", "add user to the provided cluster.")
|
||||
addUserCmd.Flags().StringP("privileges", "p", "", "add privileges separated by commas without spaces")
|
||||
rootCmd.AddCommand(addUserCmd)
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
postgresConstants "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// checkCmd represent kubectl pg check.
|
||||
var checkCmd = &cobra.Command{
|
||||
Use: "check",
|
||||
Short: "Checks the Postgres operator is installed in the k8s cluster",
|
||||
Long: `Checks that the Postgres CRD is registered in a k8s cluster.
|
||||
This means that the operator pod was able to start normally.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
check()
|
||||
},
|
||||
Example: `
|
||||
kubectl pg check
|
||||
`,
|
||||
}
|
||||
|
||||
// check validates postgresql CRD registered or not.
|
||||
func check() *v1.CustomResourceDefinition {
|
||||
config := getConfig()
|
||||
apiExtClient, err := apiextv1.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
crdInfo, err := apiExtClient.CustomResourceDefinitions().Get(context.TODO(), postgresConstants.PostgresCRDResouceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if crdInfo.Name == postgresConstants.PostgresCRDResouceName {
|
||||
fmt.Printf("Postgres Operator is installed in the k8s cluster.\n")
|
||||
} else {
|
||||
fmt.Printf("Postgres Operator is not installed in the k8s cluster.\n")
|
||||
}
|
||||
return crdInfo
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(checkCmd)
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
user "os/user"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
// connectCmd represents the kubectl pg connect command
|
||||
var connectCmd = &cobra.Command{
|
||||
Use: "connect",
|
||||
Short: "Connects to the shell prompt, psql prompt of postgres cluster",
|
||||
Long: `Connects to the shell prompt, psql prompt of postgres cluster and also to specified replica or master.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
master, _ := cmd.Flags().GetBool("master")
|
||||
replica, _ := cmd.Flags().GetString("replica")
|
||||
psql, _ := cmd.Flags().GetBool("psql")
|
||||
userName, _ := cmd.Flags().GetString("user")
|
||||
dbName, _ := cmd.Flags().GetString("database")
|
||||
|
||||
if psql {
|
||||
if userName == "" {
|
||||
userInfo, err := user.Current()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
userName = userInfo.Username
|
||||
}
|
||||
}
|
||||
if dbName == "" {
|
||||
dbName = userName
|
||||
}
|
||||
|
||||
connect(clusterName, master, replica, psql, userName, dbName)
|
||||
},
|
||||
Example: `
|
||||
#connects to the master of postgres cluster
|
||||
kubectl pg connect -c cluster -m
|
||||
|
||||
#connects to the random replica of postgres cluster
|
||||
kubectl pg connect -c cluster
|
||||
|
||||
#connects to the provided replica number of postgres cluster
|
||||
kubectl pg connect -c cluster -r 2
|
||||
|
||||
#connects to psql prompt of master for provided postgres cluster with current shell user
|
||||
kubectl pg connect -c cluster -p -m
|
||||
|
||||
#connects to psql prompt of random replica for provided postgres cluster with provided user and db
|
||||
kubectl pg connect -c cluster -p -u user01 -d db01
|
||||
`,
|
||||
}
|
||||
|
||||
func connect(clusterName string, master bool, replica string, psql bool, user string, dbName string) {
|
||||
config := getConfig()
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
podName := getPodName(clusterName, master, replica)
|
||||
var execRequest *rest.Request
|
||||
|
||||
if psql {
|
||||
execRequest = client.CoreV1().RESTClient().Post().Resource("pods").
|
||||
Name(podName).
|
||||
Namespace(getCurrentNamespace()).
|
||||
SubResource("exec").
|
||||
Param("container", "postgres").
|
||||
Param("command", "psql").
|
||||
Param("command", dbName).
|
||||
Param("command", user).
|
||||
Param("stdin", "true").
|
||||
Param("stdout", "true").
|
||||
Param("stderr", "true").
|
||||
Param("tty", "true")
|
||||
} else {
|
||||
execRequest = client.CoreV1().RESTClient().Post().Resource("pods").
|
||||
Name(podName).
|
||||
Namespace(getCurrentNamespace()).
|
||||
SubResource("exec").
|
||||
Param("container", "postgres").
|
||||
Param("command", "su").
|
||||
Param("command", "postgres").
|
||||
Param("stdin", "true").
|
||||
Param("stdout", "true").
|
||||
Param("stderr", "true").
|
||||
Param("tty", "true")
|
||||
}
|
||||
|
||||
exec, err := remotecommand.NewSPDYExecutor(config, "POST", execRequest.URL())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = exec.Stream(remotecommand.StreamOptions{
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
Tty: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
connectCmd.Flags().StringP("cluster", "c", "", "provide the cluster name.")
|
||||
connectCmd.Flags().BoolP("master", "m", false, "connect to master.")
|
||||
connectCmd.Flags().StringP("replica", "r", "", "connect to replica. Specify replica number.")
|
||||
connectCmd.Flags().BoolP("psql", "p", false, "connect to psql prompt.")
|
||||
connectCmd.Flags().StringP("user", "u", "", "provide user.")
|
||||
connectCmd.Flags().StringP("database", "d", "", "provide database name.")
|
||||
rootCmd.AddCommand(connectCmd)
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
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"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// createCmd kubectl pg create.
|
||||
var createCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Creates postgres object using manifest file",
|
||||
Long: `Creates postgres custom resource objects from a manifest file.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fileName, _ := cmd.Flags().GetString("file")
|
||||
create(fileName)
|
||||
},
|
||||
Example: `
|
||||
kubectl pg create -f cluster-manifest.yaml
|
||||
`,
|
||||
}
|
||||
|
||||
// Create postgresql resources.
|
||||
func create(fileName string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ymlFile, err := ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, _, err := decode([]byte(ymlFile), nil, &v1.Postgresql{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
postgresSql := obj.(*v1.Postgresql)
|
||||
_, err = postgresConfig.Postgresqls(postgresSql.Namespace).Create(context.TODO(), postgresSql, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("postgresql %s created.\n", postgresSql.Name)
|
||||
}
|
||||
|
||||
func init() {
|
||||
createCmd.Flags().StringP("file", "f", "", "manifest file with the cluster definition.")
|
||||
rootCmd.AddCommand(createCmd)
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
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"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// deleteCmd represents kubectl pg delete.
|
||||
var deleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Deletes postgresql object by cluster-name/manifest file",
|
||||
Long: `Deletes the postgres objects identified by a manifest file or cluster-name.
|
||||
Deleting the manifest is sufficient to delete the cluster.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
namespace, _ := cmd.Flags().GetString("namespace")
|
||||
file, _ := cmd.Flags().GetString("file")
|
||||
|
||||
if file != "" {
|
||||
deleteByFile(file)
|
||||
} else if namespace != "" {
|
||||
if len(args) != 0 {
|
||||
clusterName := args[0]
|
||||
deleteByName(clusterName, namespace)
|
||||
} else {
|
||||
fmt.Println("cluster name can't be empty")
|
||||
}
|
||||
} else {
|
||||
fmt.Println("use the flag either -n or -f to delete a resource.")
|
||||
}
|
||||
},
|
||||
Example: `
|
||||
#Deleting the postgres cluster using manifest file
|
||||
kubectl pg delete -f cluster-manifest.yaml
|
||||
|
||||
#Deleting the postgres cluster using cluster name in current namespace.
|
||||
kubectl pg delete cluster01
|
||||
|
||||
#Deleting the postgres cluster using cluster name in provided namespace
|
||||
kubectl pg delete cluster01 -n namespace01
|
||||
`,
|
||||
}
|
||||
|
||||
func deleteByFile(file string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ymlFile, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, _, err := decode([]byte(ymlFile), nil, &v1.Postgresql{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
postgresSql := obj.(*v1.Postgresql)
|
||||
_, 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
|
||||
}
|
||||
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(context.TODO(), postgresSql.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Postgresql %s deleted from %s.\n", postgresSql.Name, postgresSql.Namespace)
|
||||
}
|
||||
|
||||
func deleteByName(clusterName string, namespace string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
_, 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
|
||||
}
|
||||
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(context.TODO(), clusterName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Postgresql %s deleted from %s.\n", clusterName, namespace)
|
||||
}
|
||||
|
||||
func init() {
|
||||
namespace := getCurrentNamespace()
|
||||
deleteCmd.Flags().StringP("namespace", "n", namespace, "namespace of the cluster to be deleted.")
|
||||
deleteCmd.Flags().StringP("file", "f", "", "manifest file with the cluster definition.")
|
||||
rootCmd.AddCommand(deleteCmd)
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
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"
|
||||
)
|
||||
|
||||
// extVolumeCmd represents the extVolume command
|
||||
var extVolumeCmd = &cobra.Command{
|
||||
Use: "ext-volume",
|
||||
Short: "Increases the volume size of a given Postgres cluster",
|
||||
Long: `Extends the volume of the postgres cluster. But volume cannot be shrinked.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
if len(args) > 0 {
|
||||
volume := args[0]
|
||||
extVolume(volume, clusterName)
|
||||
} else {
|
||||
fmt.Println("please enter the cluster name with -c flag & volume in desired units")
|
||||
}
|
||||
},
|
||||
Example: `
|
||||
#Extending the volume size of provided cluster
|
||||
kubectl pg ext-volume 2Gi -c cluster01
|
||||
`,
|
||||
}
|
||||
|
||||
// extend volume with provided size & cluster name
|
||||
func extVolume(increasedVolumeSize string, clusterName string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
namespace := getCurrentNamespace()
|
||||
postgresql, err := postgresConfig.Postgresqls(namespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
oldSize, err := resource.ParseQuantity(postgresql.Spec.Volume.Size)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
newSize, err := resource.ParseQuantity(increasedVolumeSize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = strconv.Atoi(newSize.String())
|
||||
if err == nil {
|
||||
fmt.Println("provide the valid volume size with respective units i.e Ki, Mi, Gi")
|
||||
return
|
||||
}
|
||||
|
||||
if newSize.Value() > oldSize.Value() {
|
||||
patchInstances := volumePatch(newSize)
|
||||
response, err := postgresConfig.Postgresqls(namespace).Patch(context.TODO(), postgresql.Name, types.MergePatchType, patchInstances, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if postgresql.ResourceVersion != response.ResourceVersion {
|
||||
fmt.Printf("%s volume is extended to %s.\n", response.Name, increasedVolumeSize)
|
||||
} else {
|
||||
fmt.Printf("%s volume %s is unchanged.\n", response.Name, postgresql.Spec.Volume.Size)
|
||||
}
|
||||
} else if newSize.Value() == oldSize.Value() {
|
||||
fmt.Println("volume already has the desired size.")
|
||||
} else {
|
||||
fmt.Printf("volume %s size cannot be shrinked.\n", postgresql.Spec.Volume.Size)
|
||||
}
|
||||
}
|
||||
|
||||
func volumePatch(volume resource.Quantity) []byte {
|
||||
patchData := map[string]map[string]map[string]resource.Quantity{"spec": {"volume": {"size": volume}}}
|
||||
patch, err := json.Marshal(patchData)
|
||||
if err != nil {
|
||||
log.Fatal(err, "unable to parse patch to extend volume")
|
||||
}
|
||||
return patch
|
||||
}
|
||||
|
||||
func init() {
|
||||
extVolumeCmd.Flags().StringP("cluster", "c", "", "provide cluster name.")
|
||||
rootCmd.AddCommand(extVolumeCmd)
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
TrimCreateTimestamp = 6000000000
|
||||
)
|
||||
|
||||
// listCmd represents kubectl pg list.
|
||||
var listCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "Lists all the resources of kind postgresql",
|
||||
Long: `Lists all the info specific to postgresql objects.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
allNamespaces, _ := cmd.Flags().GetBool("all-namespaces")
|
||||
namespace, _ := cmd.Flags().GetString("namespace")
|
||||
if allNamespaces {
|
||||
list(allNamespaces, "")
|
||||
} else {
|
||||
list(allNamespaces, namespace)
|
||||
}
|
||||
|
||||
},
|
||||
Example: `
|
||||
#Lists postgres cluster in current namespace
|
||||
kubectl pg list
|
||||
|
||||
#Lists postgres clusters in all namespaces
|
||||
kubectl pg list -A
|
||||
`,
|
||||
}
|
||||
|
||||
// list command to list postgres.
|
||||
func list(allNamespaces bool, namespace string) {
|
||||
config := getConfig()
|
||||
postgresConfig, err := PostgresqlLister.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
listPostgres, err := postgresConfig.Postgresqls(namespace).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(listPostgres.Items) == 0 {
|
||||
if namespace != "" {
|
||||
fmt.Printf("No Postgresql clusters found in namespace: %v\n", namespace)
|
||||
} else {
|
||||
fmt.Println("No Postgresql clusters found in all namespaces")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if allNamespaces {
|
||||
listAll(listPostgres)
|
||||
} else {
|
||||
listWithNamespace(listPostgres)
|
||||
}
|
||||
}
|
||||
|
||||
func listAll(listPostgres *v1.PostgresqlList) {
|
||||
template := "%-32s%-16s%-12s%-12s%-12s%-12s%-12s\n"
|
||||
fmt.Printf(template, "NAME", "STATUS", "INSTANCES", "VERSION", "AGE", "VOLUME", "NAMESPACE")
|
||||
for _, pgObjs := range listPostgres.Items {
|
||||
fmt.Printf(template, pgObjs.Name,
|
||||
pgObjs.Status.PostgresClusterStatus,
|
||||
strconv.Itoa(int(pgObjs.Spec.NumberOfInstances)),
|
||||
pgObjs.Spec.PostgresqlParam.PgVersion,
|
||||
time.Since(pgObjs.CreationTimestamp.Time).Truncate(TrimCreateTimestamp),
|
||||
pgObjs.Spec.Size, pgObjs.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
func listWithNamespace(listPostgres *v1.PostgresqlList) {
|
||||
template := "%-32s%-16s%-12s%-12s%-12s%-12s\n"
|
||||
fmt.Printf(template, "NAME", "STATUS", "INSTANCES", "VERSION", "AGE", "VOLUME")
|
||||
for _, pgObjs := range listPostgres.Items {
|
||||
fmt.Printf(template, pgObjs.Name,
|
||||
pgObjs.Status.PostgresClusterStatus,
|
||||
strconv.Itoa(int(pgObjs.Spec.NumberOfInstances)),
|
||||
pgObjs.Spec.PostgresqlParam.PgVersion,
|
||||
time.Since(pgObjs.CreationTimestamp.Time).Truncate(TrimCreateTimestamp),
|
||||
pgObjs.Spec.Size)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
listCmd.Flags().BoolP("all-namespaces", "A", false, "list pg resources across all namespaces.")
|
||||
listCmd.Flags().StringP("namespace", "n", getCurrentNamespace(), "provide the namespace")
|
||||
rootCmd.AddCommand(listCmd)
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// logsCmd represents the logs command
|
||||
var logsCmd = &cobra.Command{
|
||||
Use: "logs",
|
||||
Short: "This will fetch the logs of the specified postgres cluster & postgres operator",
|
||||
Long: `Fetches the logs of the postgres cluster (i.e master( with -m flag) & replica with (-r 1 pod number) and without -m or -r connects to random replica`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
opLogs, _ := cmd.Flags().GetBool("operator")
|
||||
clusterName, _ := cmd.Flags().GetString("cluster")
|
||||
master, _ := cmd.Flags().GetBool("master")
|
||||
replica, _ := cmd.Flags().GetString("replica")
|
||||
|
||||
if opLogs {
|
||||
operatorLogs()
|
||||
} else {
|
||||
clusterLogs(clusterName, master, replica)
|
||||
}
|
||||
},
|
||||
Example: `
|
||||
#Fetch the logs of the postgres operator
|
||||
kubectl pg logs -o
|
||||
|
||||
#Fetch the logs of the master for provided cluster
|
||||
kubectl pg logs -c cluster01 -m
|
||||
|
||||
#Fetch the logs of the random replica for provided cluster
|
||||
kubectl pg logs -c cluster01
|
||||
|
||||
#Fetch the logs of the provided replica number of the cluster
|
||||
kubectl pg logs -c cluster01 -r 3
|
||||
`,
|
||||
}
|
||||
|
||||
func operatorLogs() {
|
||||
config := getConfig()
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
operator := getPostgresOperator(client)
|
||||
allPods, err := client.CoreV1().Pods(operator.Namespace).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var operatorPodName string
|
||||
for _, pod := range allPods.Items {
|
||||
for key, value := range pod.Labels {
|
||||
if (key == "name" && value == OperatorName) || (key == "app.kubernetes.io/name" && value == OperatorName) {
|
||||
operatorPodName = pod.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
execRequest := client.CoreV1().RESTClient().Get().Namespace(operator.Namespace).
|
||||
Name(operatorPodName).
|
||||
Resource("pods").
|
||||
SubResource("log").
|
||||
Param("follow", "--follow").
|
||||
Param("container", OperatorName)
|
||||
|
||||
readCloser, err := execRequest.Stream(context.TODO())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer readCloser.Close()
|
||||
_, err = io.Copy(os.Stdout, readCloser)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func clusterLogs(clusterName string, master bool, replica string) {
|
||||
config := getConfig()
|
||||
client, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
podName := getPodName(clusterName, master, replica)
|
||||
execRequest := client.CoreV1().RESTClient().Get().Namespace(getCurrentNamespace()).
|
||||
Name(podName).
|
||||
Resource("pods").
|
||||
SubResource("log").
|
||||
Param("follow", "--follow").
|
||||
Param("container", "postgres")
|
||||
|
||||
readCloser, err := execRequest.Stream(context.TODO())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer readCloser.Close()
|
||||
_, err = io.Copy(os.Stdout, readCloser)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(logsCmd)
|
||||
logsCmd.Flags().BoolP("operator", "o", false, "logs of operator")
|
||||
logsCmd.Flags().StringP("cluster", "c", "", "logs for the provided cluster")
|
||||
logsCmd.Flags().BoolP("master", "m", false, "Patroni logs of master")
|
||||
logsCmd.Flags().StringP("replica", "r", "", "Patroni logs of replica. Specify replica number.")
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue