├── .flake8
├── .github
├── ISSUE_TEMPLATE
│ └── postgres-operator-issue-template.md
├── PULL_REQUEST_TEMPLATE
│ └── postgres-operator-pull-request-template.md
└── workflows
│ ├── publish_ghcr_image.yaml
│ ├── run_e2e.yaml
│ └── run_tests.yaml
├── .gitignore
├── .golangci.yml
├── .zappr.yaml
├── CODEOWNERS
├── CONTRIBUTING.md
├── LICENSE
├── MAINTAINERS
├── Makefile
├── README.md
├── SECURITY.md
├── build-ci.sh
├── charts
├── postgres-operator-ui
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── index.yaml
│ ├── postgres-operator-ui-1.10.1.tgz
│ ├── postgres-operator-ui-1.11.0.tgz
│ ├── postgres-operator-ui-1.12.2.tgz
│ ├── postgres-operator-ui-1.13.0.tgz
│ ├── postgres-operator-ui-1.14.0.tgz
│ ├── postgres-operator-ui-1.9.0.tgz
│ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── clusterrole.yaml
│ │ ├── clusterrolebinding.yaml
│ │ ├── deployment.yaml
│ │ ├── ingress.yaml
│ │ ├── service.yaml
│ │ └── serviceaccount.yaml
│ └── values.yaml
└── postgres-operator
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── crds
│ ├── operatorconfigurations.yaml
│ ├── postgresqls.yaml
│ └── postgresteams.yaml
│ ├── index.yaml
│ ├── postgres-operator-1.10.1.tgz
│ ├── postgres-operator-1.11.0.tgz
│ ├── postgres-operator-1.12.2.tgz
│ ├── postgres-operator-1.13.0.tgz
│ ├── postgres-operator-1.14.0.tgz
│ ├── postgres-operator-1.9.0.tgz
│ ├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── clusterrole-postgres-pod.yaml
│ ├── clusterrole.yaml
│ ├── clusterrolebinding.yaml
│ ├── configmap.yaml
│ ├── deployment.yaml
│ ├── operatorconfiguration.yaml
│ ├── postgres-pod-priority-class.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── user-facing-clusterroles.yaml
│ └── values.yaml
├── cmd
└── main.go
├── delivery.yaml
├── docker
├── DebugDockerfile
├── Dockerfile
└── build_operator.sh
├── docs
├── administrator.md
├── developer.md
├── diagrams
│ ├── Makefile
│ ├── logo.png
│ ├── neutral_operator.excalidraw
│ ├── neutral_operator.png
│ ├── neutral_operator_dark.png
│ ├── neutral_operator_light.png
│ ├── operator.png
│ ├── operator.tex
│ ├── pgui-cluster-list.png
│ ├── pgui-cluster-startup.png
│ ├── pgui-delete-cluster.png
│ ├── pgui-finished-setup.png
│ ├── pgui-new-cluster.png
│ ├── pgui-operator-logs.png
│ ├── pgui-waiting-for-master.png
│ ├── pod.png
│ └── pod.tex
├── index.md
├── operator-ui.md
├── quickstart.md
├── reference
│ ├── cluster_manifest.md
│ ├── command_line_and_environment.md
│ └── operator_parameters.md
└── user.md
├── e2e
├── Dockerfile
├── Makefile
├── README.md
├── exec.sh
├── exec_into_env.sh
├── kind-cluster-postgres-operator-e2e-tests.yaml
├── requirements.txt
├── run.sh
├── scripts
│ ├── cleanup.sh
│ ├── get_logs.sh
│ └── watch_objects.sh
└── tests
│ ├── __init__.py
│ ├── k8s_api.py
│ └── test_e2e.py
├── go.mod
├── go.sum
├── hack
├── custom-boilerplate.go.txt
├── tools.go
├── update-codegen.sh
└── verify-codegen.sh
├── kubectl-pg
├── README.md
├── build.sh
├── cmd
│ ├── addDb.go
│ ├── addUser.go
│ ├── check.go
│ ├── connect.go
│ ├── create.go
│ ├── delete.go
│ ├── extVolume.go
│ ├── list.go
│ ├── logs.go
│ ├── root.go
│ ├── scale.go
│ ├── update.go
│ ├── util.go
│ └── version.go
├── go.mod
├── go.sum
└── main.go
├── logical-backup
├── Dockerfile
└── dump.sh
├── manifests
├── api-service.yaml
├── complete-postgres-manifest.yaml
├── configmap.yaml
├── custom-team-membership.yaml
├── e2e-storage-class.yaml
├── fake-teams-api.yaml
├── fes.crd.yaml
├── infrastructure-roles-configmap.yaml
├── infrastructure-roles-new.yaml
├── infrastructure-roles.yaml
├── kustomization.yaml
├── minimal-fake-pooler-deployment.yaml
├── minimal-master-replica-svcmonitor.yaml
├── minimal-postgres-lowest-version-manifest.yaml
├── minimal-postgres-manifest.yaml
├── operator-service-account-rbac-openshift.yaml
├── operator-service-account-rbac.yaml
├── operatorconfiguration.crd.yaml
├── platform-credentials.yaml
├── postgres-operator.yaml
├── postgres-pod-priority-class.yaml
├── postgresql-operator-default-configuration.yaml
├── postgresql.crd.yaml
├── postgresteam.crd.yaml
├── standby-manifest.yaml
└── user-facing-clusterroles.yaml
├── mkdocs.yml
├── mocks
└── mocks.go
├── pkg
├── apis
│ ├── acid.zalan.do
│ │ ├── register.go
│ │ └── v1
│ │ │ ├── const.go
│ │ │ ├── crds.go
│ │ │ ├── doc.go
│ │ │ ├── marshal.go
│ │ │ ├── operator_configuration_type.go
│ │ │ ├── postgres_team_type.go
│ │ │ ├── postgresql_type.go
│ │ │ ├── register.go
│ │ │ ├── util.go
│ │ │ ├── util_test.go
│ │ │ └── zz_generated.deepcopy.go
│ └── zalando.org
│ │ ├── register.go
│ │ └── v1
│ │ ├── fabriceventstream.go
│ │ ├── register.go
│ │ └── zz_generated.deepcopy.go
├── apiserver
│ ├── apiserver.go
│ └── apiserver_test.go
├── cluster
│ ├── cluster.go
│ ├── cluster_test.go
│ ├── connection_pooler.go
│ ├── connection_pooler_new_test.go
│ ├── connection_pooler_test.go
│ ├── database.go
│ ├── exec.go
│ ├── filesystems.go
│ ├── k8sres.go
│ ├── k8sres_test.go
│ ├── majorversionupgrade.go
│ ├── pod.go
│ ├── pod_test.go
│ ├── resources.go
│ ├── streams.go
│ ├── streams_test.go
│ ├── sync.go
│ ├── sync_test.go
│ ├── types.go
│ ├── util.go
│ ├── util_test.go
│ ├── volumes.go
│ └── volumes_test.go
├── controller
│ ├── controller.go
│ ├── logs_and_api.go
│ ├── node.go
│ ├── node_test.go
│ ├── operator_config.go
│ ├── pod.go
│ ├── postgresql.go
│ ├── postgresql_test.go
│ ├── types.go
│ ├── util.go
│ └── util_test.go
├── generated
│ ├── clientset
│ │ └── versioned
│ │ │ ├── clientset.go
│ │ │ ├── doc.go
│ │ │ ├── fake
│ │ │ ├── clientset_generated.go
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ ├── scheme
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ └── typed
│ │ │ ├── acid.zalan.do
│ │ │ └── v1
│ │ │ │ ├── acid.zalan.do_client.go
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake_acid.zalan.do_client.go
│ │ │ │ ├── fake_operatorconfiguration.go
│ │ │ │ ├── fake_postgresql.go
│ │ │ │ └── fake_postgresteam.go
│ │ │ │ ├── generated_expansion.go
│ │ │ │ ├── operatorconfiguration.go
│ │ │ │ ├── postgresql.go
│ │ │ │ └── postgresteam.go
│ │ │ └── zalando.org
│ │ │ └── v1
│ │ │ ├── doc.go
│ │ │ ├── fabriceventstream.go
│ │ │ ├── fake
│ │ │ ├── doc.go
│ │ │ ├── fake_fabriceventstream.go
│ │ │ └── fake_zalando.org_client.go
│ │ │ ├── generated_expansion.go
│ │ │ └── zalando.org_client.go
│ ├── informers
│ │ └── externalversions
│ │ │ ├── acid.zalan.do
│ │ │ ├── interface.go
│ │ │ └── v1
│ │ │ │ ├── interface.go
│ │ │ │ ├── postgresql.go
│ │ │ │ └── postgresteam.go
│ │ │ ├── factory.go
│ │ │ ├── generic.go
│ │ │ ├── internalinterfaces
│ │ │ └── factory_interfaces.go
│ │ │ └── zalando.org
│ │ │ ├── interface.go
│ │ │ └── v1
│ │ │ ├── fabriceventstream.go
│ │ │ └── interface.go
│ └── listers
│ │ ├── acid.zalan.do
│ │ └── v1
│ │ │ ├── expansion_generated.go
│ │ │ ├── postgresql.go
│ │ │ └── postgresteam.go
│ │ └── zalando.org
│ │ └── v1
│ │ ├── expansion_generated.go
│ │ └── fabriceventstream.go
├── spec
│ ├── types.go
│ └── types_test.go
├── teams
│ ├── postgres_team.go
│ └── postgres_team_test.go
└── util
│ ├── config
│ ├── config.go
│ ├── config_test.go
│ └── util.go
│ ├── constants
│ ├── annotations.go
│ ├── aws.go
│ ├── kubernetes.go
│ ├── pooler.go
│ ├── postgresql.go
│ ├── roles.go
│ ├── streams.go
│ └── units.go
│ ├── filesystems
│ ├── ext234.go
│ └── filesystems.go
│ ├── httpclient
│ └── httpclient.go
│ ├── k8sutil
│ └── k8sutil.go
│ ├── nicediff
│ └── diff.go
│ ├── patroni
│ ├── patroni.go
│ └── patroni_test.go
│ ├── retryutil
│ ├── retry_util.go
│ └── retry_util_test.go
│ ├── ringlog
│ └── ringlog.go
│ ├── teams
│ ├── teams.go
│ └── teams_test.go
│ ├── users
│ └── users.go
│ ├── util.go
│ ├── util_test.go
│ └── volumes
│ ├── ebs.go
│ ├── ebs_test.go
│ ├── volumes.go
│ └── volumes_test.go
├── run_operator_locally.sh
└── ui
├── .dockerignore
├── Dockerfile
├── MANIFEST.in
├── Makefile
├── app
├── .eslintignore
├── .eslintrc.yml
├── README.rst
├── package.json
├── src
│ ├── app.js
│ ├── app.tag.pug
│ ├── edit.tag.pug
│ ├── help-edit.tag.pug
│ ├── help-general.tag.pug
│ ├── logs.tag.pug
│ ├── new.tag.pug
│ ├── postgresql.tag.pug
│ ├── postgresqls.tag.pug
│ ├── prism.js
│ ├── restore.tag.pug
│ └── status.tag.pug
└── webpack.config.js
├── manifests
├── deployment.yaml
├── ingress.yaml
├── kustomization.yaml
├── service.yaml
└── ui-service-account-rbac.yaml
├── operator_ui
├── __init__.py
├── __main__.py
├── adapters
│ ├── __init__.py
│ └── logger.py
├── backoff.py
├── cluster_discovery.py
├── main.py
├── mock.py
├── spiloutils.py
├── static
│ ├── favicon-96x96.png
│ ├── prism.css
│ ├── prism.js
│ └── styles.css
├── templates
│ └── index.html
├── update.py
└── utils.py
├── requirements.txt
├── run_local.sh
├── setup.py
├── start_server.sh
└── tox.ini
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | exclude=.git,__pycache__
3 | max-line-length=120
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/postgres-operator-issue-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Postgres Operator issue template
3 | about: How are you using the operator?
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | Please, answer some short questions which should help us to understand your problem / question better?
11 |
12 | - **Which image of the operator are you using?** e.g. ghcr.io/zalando/postgres-operator:v1.13.0
13 | - **Where do you run it - cloud or metal? Kubernetes or OpenShift?** [AWS K8s | GCP ... | Bare Metal K8s]
14 | - **Are you running Postgres Operator in production?** [yes | no]
15 | - **Type of issue?** [Bug report, question, feature request, etc.]
16 |
17 | Some general remarks when posting a bug report:
18 | - Please, check the operator, pod (Patroni) and postgresql logs first. When copy-pasting many log lines please do it in a separate GitHub gist together with your Postgres CRD and configuration manifest.
19 | - If you feel this issue might be more related to the [Spilo](https://github.com/zalando/spilo/issues) docker image or [Patroni](https://github.com/zalando/patroni/issues), consider opening issues in the respective repos.
20 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/postgres-operator-pull-request-template.md:
--------------------------------------------------------------------------------
1 | ## Problem description
2 |
3 |
4 |
5 | ## Linked issues
6 |
7 |
8 |
9 | ## Checklist
10 |
11 | Thanks for submitting a pull request to the Postgres Operator project.
12 | Please, ensure your contribution matches the following items:
13 |
14 | - [ ] Your go code is [formatted](https://blog.golang.org/gofmt). Your IDE should do it automatically for you.
15 | - [ ] You have updated [generated code](https://github.com/zalando/postgres-operator/blob/master/docs/developer.md#code-generation) when introducing new fields to the `acid.zalan.do` api package.
16 | - [ ] New [configuration options](https://github.com/zalando/postgres-operator/blob/master/docs/developer.md#introduce-additional-configuration-parameters) are reflected in CRD validation, helm charts and sample manifests.
17 | - [ ] New functionality is covered by [unit](https://github.com/zalando/postgres-operator/blob/master/docs/developer.md#unit-tests) and/or [e2e](https://github.com/zalando/postgres-operator/blob/master/docs/developer.md#end-to-end-tests) tests.
18 | - [ ] You have checked existing open PRs for possible overlay and referenced them.
19 |
--------------------------------------------------------------------------------
/.github/workflows/publish_ghcr_image.yaml:
--------------------------------------------------------------------------------
1 | name: Publish multiarch postgres-operator images on ghcr.io
2 |
3 | env:
4 | REGISTRY: ghcr.io
5 | IMAGE_NAME: ${{ github.repository }}
6 | IMAGE_NAME_UI: ${{ github.repository }}-ui
7 |
8 | on:
9 | push:
10 | tags:
11 | - '*'
12 |
13 | jobs:
14 | publish:
15 | name: Build, test and push image
16 | runs-on: ubuntu-latest
17 | permissions:
18 | contents: read
19 | packages: write
20 | steps:
21 | - name: Checkout repository
22 | uses: actions/checkout@v3
23 |
24 | - uses: actions/setup-go@v2
25 | with:
26 | go-version: "^1.23.4"
27 |
28 | - name: Run unit tests
29 | run: make deps mocks test
30 |
31 | - name: Define image name
32 | id: image
33 | run: |
34 | OPERATOR_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF/refs\/tags\//}"
35 | echo "OPERATOR_IMAGE=$OPERATOR_IMAGE" >> $GITHUB_OUTPUT
36 |
37 | - name: Define UI image name
38 | id: image_ui
39 | run: |
40 | UI_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME_UI }}:${GITHUB_REF/refs\/tags\//}"
41 | echo "UI_IMAGE=$UI_IMAGE" >> $GITHUB_OUTPUT
42 |
43 | - name: Define logical backup image name
44 | id: image_lb
45 | run: |
46 | BACKUP_IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/logical-backup:${GITHUB_REF_NAME}"
47 | echo "BACKUP_IMAGE=$BACKUP_IMAGE" >> $GITHUB_OUTPUT
48 |
49 | - name: Set up QEMU
50 | uses: docker/setup-qemu-action@v2
51 |
52 | - name: Set up Docker Buildx
53 | uses: docker/setup-buildx-action@v2
54 |
55 | - name: Login to GHCR
56 | uses: docker/login-action@v2
57 | with:
58 | registry: ${{ env.REGISTRY }}
59 | username: ${{ github.actor }}
60 | password: ${{ secrets.GITHUB_TOKEN }}
61 |
62 | - name: Build and push multiarch operator image to ghcr
63 | uses: docker/build-push-action@v3
64 | with:
65 | context: .
66 | file: docker/Dockerfile
67 | push: true
68 | build-args: BASE_IMAGE=alpine:3
69 | tags: "${{ steps.image.outputs.OPERATOR_IMAGE }}"
70 | platforms: linux/amd64,linux/arm64
71 |
72 | - name: Build and push multiarch ui image to ghcr
73 | uses: docker/build-push-action@v3
74 | with:
75 | context: ui
76 | push: true
77 | build-args: BASE_IMAGE=python:3.11-slim
78 | tags: "${{ steps.image_ui.outputs.UI_IMAGE }}"
79 | platforms: linux/amd64,linux/arm64
80 |
81 | - name: Build and push multiarch logical-backup image to ghcr
82 | uses: docker/build-push-action@v3
83 | with:
84 | context: logical-backup
85 | push: true
86 | build-args: BASE_IMAGE=ubuntu:22.04
87 | tags: "${{ steps.image_lb.outputs.BACKUP_IMAGE }}"
88 | platforms: linux/amd64,linux/arm64
89 |
--------------------------------------------------------------------------------
/.github/workflows/run_e2e.yaml:
--------------------------------------------------------------------------------
1 | name: operator-e2e-tests
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - master
8 |
9 | jobs:
10 | tests:
11 | name: End-2-End tests
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v1
15 | - uses: actions/setup-go@v2
16 | with:
17 | go-version: "^1.23.4"
18 | - name: Make dependencies
19 | run: make deps mocks
20 | - name: Code generation
21 | run: make codegen
22 | - name: Run unit tests
23 | run: make test
24 | - name: Run end-2-end tests
25 | run: make e2e
26 |
--------------------------------------------------------------------------------
/.github/workflows/run_tests.yaml:
--------------------------------------------------------------------------------
1 | name: operator-tests
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - master
8 |
9 | jobs:
10 | tests:
11 | name: Unit tests and coverage
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: actions/setup-go@v2
16 | with:
17 | go-version: "^1.23.4"
18 | - name: Make dependencies
19 | run: make deps mocks
20 | - name: Compile
21 | run: make linux
22 | - name: Run unit tests
23 | run: go test -race -covermode atomic -coverprofile=coverage.out ./...
24 | - name: Convert coverage to lcov
25 | uses: jandelgado/gcov2lcov-action@v1.1.1
26 | - name: Coveralls
27 | uses: coverallsapp/github-action@master
28 | with:
29 | github-token: ${{ secrets.GITHUB_TOKEN }}
30 | path-to-lcov: coverage.lcov
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
2 | *.o
3 | *.a
4 | *.so
5 |
6 | # Folders
7 | _obj
8 | _test
9 | _manifests
10 | _tmp
11 | github.com
12 |
13 | # Architecture specific extensions/prefixes
14 | *.[568vq]
15 | [568vq].out
16 |
17 | *.cgo1.go
18 | *.cgo2.c
19 | _cgo_defun.c
20 | _cgo_gotypes.go
21 | _cgo_export.*
22 |
23 | _testmain.go
24 |
25 | *.exe
26 | *.test
27 | *.prof
28 | /vendor/
29 | /kubectl-pg/vendor/
30 | /build/
31 | /docker/build/
32 | /github.com/
33 | .idea
34 | .vscode
35 |
36 | scm-source.json
37 |
38 | # diagrams
39 | *.aux
40 | *.log
41 |
42 | # Python
43 | # Adapted from https://github.com/github/gitignore/blob/master/Python.gitignore
44 |
45 | # Byte-compiled / optimized / DLL files
46 | __pycache__/
47 | *.py[cod]
48 | *$py.class
49 |
50 | # Distribution / packaging
51 | .Python
52 | ui/app/node_modules
53 | ui/operator_ui/static/build
54 | build/
55 | develop-eggs/
56 | dist/
57 | downloads/
58 | eggs/
59 | .eggs/
60 | lib/
61 | lib64/
62 | parts/
63 | sdist/
64 | var/
65 | wheels/
66 | pip-wheel-metadata/
67 | share/python-wheels/
68 | *.egg-info/
69 | .installed.cfg
70 | *.egg
71 | MANIFEST
72 |
73 | # PyInstaller
74 | # Usually these files are written by a python script from a template
75 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
76 | *.manifest
77 | *.spec
78 |
79 | # Installer logs
80 | pip-log.txt
81 | pip-delete-this-directory.txt
82 |
83 | # Unit test / coverage reports
84 | htmlcov/
85 | .tox/
86 | .nox/
87 | .coverage
88 | .coverage.*
89 | .cache
90 | nosetests.xml
91 | coverage.xml
92 | *.cover
93 | .hypothesis/
94 | .pytest_cache/
95 |
96 | # e2e tests
97 | e2e/manifests
98 | e2e/tls
99 |
100 | # Translations
101 | *.mo
102 | *.pot
103 |
104 | mocks
105 |
106 | ui/.npm/
107 |
108 | .DS_Store
109 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | # https://github.com/golangci/golangci/wiki/Configuration
2 |
3 | service:
4 | prepare:
5 | - make deps
6 |
--------------------------------------------------------------------------------
/.zappr.yaml:
--------------------------------------------------------------------------------
1 | # for github.com
2 | X-Zalando-Team: "acid"
3 | # type should be one of [code, doc, config, tools, secrets]
4 | # code will be the default value, if X-Zalando-Type is not found in .zappr.yml
5 | X-Zalando-Type: code
6 |
7 | approvals:
8 | groups:
9 | zalando:
10 | minimum: 2
11 | from:
12 | orgs:
13 | - zalando
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # global owners
2 | * @sdudoladov @Jan-M @FxKu @jopadi @idanovinda @hughcapet @macedigital
3 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing guidelines
2 |
3 | Wanna contribute to the Postgres Operator? Yay - here is how!
4 |
5 | ## Reporting issues
6 |
7 | Before filing an issue, if you have a question about Postgres Operator or have
8 | a problem using it, please read the [concepts](docs/index.md) page or use the
9 | different guides that we provide for [users](docs/user.md),
10 | [developers](docs/developer.md) or [admins](docs/administrator). Also double
11 | check with the current issues on our [Issues Tracker](https://github.com/zalando/postgres-operator/issues).
12 |
13 | ## Contributing a pull request
14 |
15 | 1. Submit a comment to the relevant issue or create a new issue describing your
16 | proposed change.
17 | 2. Do a fork, develop and test your code changes.
18 | 3. Include documentation
19 | 4. Submit a pull request.
20 |
21 | You'll get feedback about your pull request as soon as possible.
22 |
23 | Happy Operator hacking ;-)
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2024 Zalando SE
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MAINTAINERS:
--------------------------------------------------------------------------------
1 | Sergey Dudoladov <sergey.dudoladov@zalando.de>
2 | Felix Kunde <felix.kunde@zalando.de>
3 | Jan Mussler <jan.mussler@zalando.de>
4 | Jociele Padilha <jociele.padilha@zalando.de>
5 | Ida Novindasari <ida.novindasari@zalando.de>
6 | Polina Bungina <polina.bungina@zalando.de>
7 | Matthias Adler <matthias.adler@zalando.de>
8 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: clean local test linux macos mocks docker push e2e
2 |
3 | BINARY ?= postgres-operator
4 | BUILD_FLAGS ?= -v
5 | CGO_ENABLED ?= 0
6 | ifeq ($(RACE),1)
7 | BUILD_FLAGS += -race -a
8 | CGO_ENABLED=1
9 | endif
10 |
11 | LOCAL_BUILD_FLAGS ?= $(BUILD_FLAGS)
12 | LDFLAGS ?= -X=main.version=$(VERSION)
13 | DOCKERDIR = docker
14 |
15 | IMAGE ?= registry.opensource.zalan.do/acid/$(BINARY)
16 | TAG ?= $(VERSION)
17 | GITHEAD = $(shell git rev-parse --short HEAD)
18 | GITURL = $(shell git config --get remote.origin.url)
19 | GITSTATUS = $(shell git status --porcelain || echo "no changes")
20 | SOURCES = cmd/main.go
21 | VERSION ?= $(shell git describe --tags --always --dirty)
22 | DIRS := cmd pkg
23 | PKG := `go list ./... | grep -v /vendor/`
24 |
25 | ifeq ($(DEBUG),1)
26 | DOCKERFILE = DebugDockerfile
27 | DEBUG_POSTFIX := -debug-$(shell date hhmmss)
28 | BUILD_FLAGS += -gcflags "-N -l"
29 | else
30 | DOCKERFILE = Dockerfile
31 | endif
32 |
33 | ifeq ($(FRESH),1)
34 | DEBUG_FRESH=$(shell date +"%H-%M-%S")
35 | endif
36 |
37 | ifdef CDP_PULL_REQUEST_NUMBER
38 | CDP_TAG := -${CDP_BUILD_VERSION}
39 | endif
40 |
41 | ifndef GOPATH
42 | GOPATH := $(HOME)/go
43 | endif
44 |
45 | PATH := $(GOPATH)/bin:$(PATH)
46 | SHELL := env PATH=$(PATH) $(SHELL)
47 |
48 | default: local
49 |
50 | clean:
51 | rm -rf build
52 |
53 | local: ${SOURCES}
54 | hack/verify-codegen.sh
55 | CGO_ENABLED=${CGO_ENABLED} go build -o build/${BINARY} $(LOCAL_BUILD_FLAGS) -ldflags "$(LDFLAGS)" $^
56 |
57 | linux: ${SOURCES}
58 | GOOS=linux GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} go build -o build/linux/${BINARY} ${BUILD_FLAGS} -ldflags "$(LDFLAGS)" $^
59 |
60 | macos: ${SOURCES}
61 | GOOS=darwin GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} go build -o build/macos/${BINARY} ${BUILD_FLAGS} -ldflags "$(LDFLAGS)" $^
62 |
63 | docker: ${DOCKERDIR}/${DOCKERFILE}
64 | echo `(env)`
65 | echo "Tag ${TAG}"
66 | echo "Version ${VERSION}"
67 | echo "CDP tag ${CDP_TAG}"
68 | echo "git describe $(shell git describe --tags --always --dirty)"
69 | docker build --rm -t "$(IMAGE):$(TAG)$(CDP_TAG)$(DEBUG_FRESH)$(DEBUG_POSTFIX)" -f "${DOCKERDIR}/${DOCKERFILE}" --build-arg VERSION="${VERSION}" .
70 |
71 | indocker-race:
72 | docker run --rm -v "${GOPATH}":"${GOPATH}" -e GOPATH="${GOPATH}" -e RACE=1 -w ${PWD} golang:1.23.4 bash -c "make linux"
73 |
74 | push:
75 | docker push "$(IMAGE):$(TAG)$(CDP_TAG)"
76 |
77 | mocks:
78 | GO111MODULE=on go generate ./...
79 |
80 | tools:
81 | GO111MODULE=on go get k8s.io/client-go@kubernetes-1.30.4
82 | GO111MODULE=on go install github.com/golang/mock/mockgen@v1.6.0
83 | GO111MODULE=on go mod tidy
84 |
85 | fmt:
86 | @gofmt -l -w -s $(DIRS)
87 |
88 | vet:
89 | @go vet $(PKG)
90 | @staticcheck $(PKG)
91 |
92 | deps: tools
93 | GO111MODULE=on go mod vendor
94 |
95 | test:
96 | hack/verify-codegen.sh
97 | GO111MODULE=on go test ./...
98 |
99 | codegen:
100 | hack/update-codegen.sh
101 |
102 | e2e: docker # build operator image to be tested
103 | cd e2e; make e2etest
104 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security
2 |
3 | If you have discovered a security vulnerability, please email tech-security@zalando.de.
4 |
--------------------------------------------------------------------------------
/build-ci.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e -x
3 |
4 | team_repo="$GOPATH/src/github.com/zalando/"
5 | project_dir="$team_repo/postgres-operator"
6 |
7 | mkdir -p "$team_repo"
8 |
9 | ln -s "$PWD" "$project_dir"
10 | cd "$project_dir"
11 |
12 | make deps clean docker push
13 |
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *~
18 | # Various IDEs
19 | .project
20 | .idea/
21 | *.tmproj
22 | .vscode/
23 |
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: postgres-operator-ui
3 | version: 1.14.0
4 | appVersion: 1.14.0
5 | home: https://github.com/zalando/postgres-operator
6 | description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
7 | keywords:
8 | - postgres
9 | - operator
10 | - ui
11 | - cloud-native
12 | - patroni
13 | - spilo
14 | maintainers:
15 | - name: Zalando
16 | email: opensource@zalando.de
17 | sources:
18 | - https://github.com/zalando/postgres-operator
19 | engine: gotpl
20 |
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/postgres-operator-ui-1.10.1.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator-ui/postgres-operator-ui-1.10.1.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/postgres-operator-ui-1.11.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator-ui/postgres-operator-ui-1.11.0.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/postgres-operator-ui-1.12.2.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator-ui/postgres-operator-ui-1.12.2.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/postgres-operator-ui-1.13.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator-ui/postgres-operator-ui-1.13.0.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/postgres-operator-ui-1.14.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator-ui/postgres-operator-ui-1.14.0.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/postgres-operator-ui-1.9.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator-ui/postgres-operator-ui-1.9.0.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | To verify that postgres-operator has started, run:
2 |
3 | kubectl --namespace={{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ template "postgres-operator-ui.name" . }}"
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{/*
3 | Expand the name of the chart.
4 | */}}
5 | {{- define "postgres-operator-ui.name" -}}
6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
7 | {{- end -}}
8 |
9 | {{/*
10 | Create a default fully qualified app name.
11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
12 | If release name contains chart name it will be used as a full name.
13 | */}}
14 | {{- define "postgres-operator-ui.fullname" -}}
15 | {{- if .Values.fullnameOverride -}}
16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
17 | {{- else -}}
18 | {{- $name := default .Chart.Name .Values.nameOverride -}}
19 | {{- if contains $name .Release.Name -}}
20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}}
21 | {{- else -}}
22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
23 | {{- end -}}
24 | {{- end -}}
25 | {{- end -}}
26 |
27 | {{/*
28 | Create a service account name.
29 | */}}
30 | {{- define "postgres-operator-ui.serviceAccountName" -}}
31 | {{ default (include "postgres-operator-ui.fullname" .) .Values.serviceAccount.name }}
32 | {{- end -}}
33 |
34 | {{/*
35 | Create chart name and version as used by the chart label.
36 | */}}
37 | {{- define "postgres-operator-ui.chart" -}}
38 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
39 | {{- end -}}
40 |
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/templates/clusterrole.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.rbac.create }}
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: {{ include "postgres-operator-ui.serviceAccountName" . }}
6 | labels:
7 | app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
8 | helm.sh/chart: {{ template "postgres-operator-ui.chart" . }}
9 | app.kubernetes.io/managed-by: {{ .Release.Service }}
10 | app.kubernetes.io/instance: {{ .Release.Name }}
11 | rules:
12 | - apiGroups:
13 | - acid.zalan.do
14 | resources:
15 | - postgresqls
16 | verbs:
17 | - create
18 | - delete
19 | - get
20 | - list
21 | - patch
22 | - update
23 | - apiGroups:
24 | - ""
25 | resources:
26 | - pods
27 | verbs:
28 | - get
29 | - list
30 | - watch
31 | - apiGroups:
32 | - ""
33 | resources:
34 | - services
35 | verbs:
36 | - get
37 | - list
38 | - apiGroups:
39 | - apps
40 | resources:
41 | - deployments
42 | - statefulsets
43 | verbs:
44 | - get
45 | - list
46 | - apiGroups:
47 | - ""
48 | resources:
49 | - namespaces
50 | verbs:
51 | - get
52 | - list
53 | {{ end }}
54 |
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/templates/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.rbac.create }}
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRoleBinding
4 | metadata:
5 | name: {{ include "postgres-operator-ui.serviceAccountName" . }}
6 | labels:
7 | app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
8 | helm.sh/chart: {{ template "postgres-operator-ui.chart" . }}
9 | app.kubernetes.io/managed-by: {{ .Release.Service }}
10 | app.kubernetes.io/instance: {{ .Release.Name }}
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: {{ include "postgres-operator-ui.serviceAccountName" . }}
15 | subjects:
16 | - kind: ServiceAccount
17 | name: {{ include "postgres-operator-ui.serviceAccountName" . }}
18 | namespace: {{ .Release.Namespace }}
19 | {{ end }}
20 |
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/templates/ingress.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.ingress.enabled -}}
2 | {{- $fullName := include "postgres-operator-ui.fullname" . -}}
3 | {{- $svcPort := .Values.service.port -}}
4 |
5 | {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
6 | apiVersion: networking.k8s.io/v1
7 | {{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
8 | apiVersion: networking.k8s.io/v1beta1
9 | {{- else -}}
10 | apiVersion: extensions/v1beta1
11 | {{- end }}
12 | kind: Ingress
13 | metadata:
14 | name: {{ $fullName }}
15 | namespace: {{ .Release.Namespace }}
16 | labels:
17 | app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
18 | helm.sh/chart: {{ template "postgres-operator-ui.chart" . }}
19 | app.kubernetes.io/managed-by: {{ .Release.Service }}
20 | app.kubernetes.io/instance: {{ .Release.Name }}
21 | {{- with .Values.ingress.annotations }}
22 | annotations:
23 | {{- toYaml . | nindent 4 }}
24 | {{- end }}
25 | spec:
26 | {{- if .Values.ingress.ingressClassName }}
27 | ingressClassName: {{ .Values.ingress.ingressClassName }}
28 | {{- end }}
29 | {{- if .Values.ingress.tls }}
30 | tls:
31 | {{- range .Values.ingress.tls }}
32 | - hosts:
33 | {{- range .hosts }}
34 | - {{ . | quote }}
35 | {{- end }}
36 | secretName: {{ .secretName }}
37 | {{- end }}
38 | {{- end }}
39 | rules:
40 | {{- range .Values.ingress.hosts }}
41 | - host: {{ .host | quote }}
42 | http:
43 | paths:
44 | {{- range .paths }}
45 | - path: {{ . }}
46 | {{ if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion -}}
47 | pathType: Prefix
48 | backend:
49 | service:
50 | name: {{ $fullName }}
51 | port:
52 | number: {{ $svcPort }}
53 | {{- else -}}
54 | backend:
55 | serviceName: {{ $fullName }}
56 | servicePort: {{ $svcPort }}
57 | {{- end -}}
58 | {{- end }}
59 | {{- end }}
60 | {{- end }}
61 |
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/templates/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
6 | helm.sh/chart: {{ template "postgres-operator-ui.chart" . }}
7 | app.kubernetes.io/managed-by: {{ .Release.Service }}
8 | app.kubernetes.io/instance: {{ .Release.Name }}
9 | {{- with .Values.service.annotations }}
10 | annotations:
11 | {{- toYaml . | nindent 4 }}
12 | {{- end }}
13 | name: {{ template "postgres-operator-ui.fullname" . }}
14 | namespace: {{ .Release.Namespace }}
15 | spec:
16 | ports:
17 | - port: {{ .Values.service.port }}
18 | targetPort: 8081
19 | {{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }}
20 | nodePort: {{ .Values.service.nodePort }}
21 | {{- end }}
22 | protocol: TCP
23 | selector:
24 | app.kubernetes.io/instance: {{ .Release.Name }}
25 | app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
26 | type: {{ .Values.service.type }}
27 |
28 |
29 |
--------------------------------------------------------------------------------
/charts/postgres-operator-ui/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.serviceAccount.create }}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "postgres-operator-ui.serviceAccountName" . }}
6 | namespace: {{ .Release.Namespace }}
7 | labels:
8 | app.kubernetes.io/name: {{ template "postgres-operator-ui.name" . }}
9 | helm.sh/chart: {{ template "postgres-operator-ui.chart" . }}
10 | app.kubernetes.io/managed-by: {{ .Release.Service }}
11 | app.kubernetes.io/instance: {{ .Release.Name }}
12 | {{ end }}
13 |
--------------------------------------------------------------------------------
/charts/postgres-operator/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *~
18 | # Various IDEs
19 | .project
20 | .idea/
21 | *.tmproj
22 |
--------------------------------------------------------------------------------
/charts/postgres-operator/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: postgres-operator
3 | version: 1.14.0
4 | appVersion: 1.14.0
5 | home: https://github.com/zalando/postgres-operator
6 | description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
7 | keywords:
8 | - postgres
9 | - operator
10 | - cloud-native
11 | - patroni
12 | - spilo
13 | maintainers:
14 | - name: Zalando
15 | email: opensource@zalando.de
16 | sources:
17 | - https://github.com/zalando/postgres-operator
18 | engine: gotpl
19 |
--------------------------------------------------------------------------------
/charts/postgres-operator/crds/postgresteams.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apiextensions.k8s.io/v1
2 | kind: CustomResourceDefinition
3 | metadata:
4 | name: postgresteams.acid.zalan.do
5 | labels:
6 | app.kubernetes.io/name: postgres-operator
7 | spec:
8 | group: acid.zalan.do
9 | names:
10 | kind: PostgresTeam
11 | listKind: PostgresTeamList
12 | plural: postgresteams
13 | singular: postgresteam
14 | shortNames:
15 | - pgteam
16 | categories:
17 | - all
18 | scope: Namespaced
19 | versions:
20 | - name: v1
21 | served: true
22 | storage: true
23 | subresources:
24 | status: {}
25 | schema:
26 | openAPIV3Schema:
27 | type: object
28 | required:
29 | - kind
30 | - apiVersion
31 | - spec
32 | properties:
33 | kind:
34 | type: string
35 | enum:
36 | - PostgresTeam
37 | apiVersion:
38 | type: string
39 | enum:
40 | - acid.zalan.do/v1
41 | spec:
42 | type: object
43 | properties:
44 | additionalSuperuserTeams:
45 | type: object
46 | description: "Map for teamId and associated additional superuser teams"
47 | additionalProperties:
48 | type: array
49 | nullable: true
50 | description: "List of teams to become Postgres superusers"
51 | items:
52 | type: string
53 | additionalTeams:
54 | type: object
55 | description: "Map for teamId and associated additional teams"
56 | additionalProperties:
57 | type: array
58 | nullable: true
59 | description: "List of teams whose members will also be added to the Postgres cluster"
60 | items:
61 | type: string
62 | additionalMembers:
63 | type: object
64 | description: "Map for teamId and associated additional users"
65 | additionalProperties:
66 | type: array
67 | nullable: true
68 | description: "List of users who will also be added to the Postgres cluster"
69 | items:
70 | type: string
71 |
--------------------------------------------------------------------------------
/charts/postgres-operator/postgres-operator-1.10.1.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator/postgres-operator-1.10.1.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator/postgres-operator-1.11.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator/postgres-operator-1.11.0.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator/postgres-operator-1.12.2.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator/postgres-operator-1.12.2.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator/postgres-operator-1.13.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator/postgres-operator-1.13.0.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator/postgres-operator-1.14.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator/postgres-operator-1.14.0.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator/postgres-operator-1.9.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/charts/postgres-operator/postgres-operator-1.9.0.tgz
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | To verify that postgres-operator has started, run:
2 |
3 | kubectl --namespace={{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ template "postgres-operator.name" . }}"
4 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{/*
3 | Expand the name of the chart.
4 | */}}
5 | {{- define "postgres-operator.name" -}}
6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
7 | {{- end -}}
8 |
9 | {{/*
10 | Create a default fully qualified app name.
11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
12 | If release name contains chart name it will be used as a full name.
13 | */}}
14 | {{- define "postgres-operator.fullname" -}}
15 | {{- if .Values.fullnameOverride -}}
16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
17 | {{- else -}}
18 | {{- $name := default .Chart.Name .Values.nameOverride -}}
19 | {{- if contains $name .Release.Name -}}
20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}}
21 | {{- else -}}
22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
23 | {{- end -}}
24 | {{- end -}}
25 | {{- end -}}
26 |
27 | {{/*
28 | Create a service account name.
29 | */}}
30 | {{- define "postgres-operator.serviceAccountName" -}}
31 | {{ default (include "postgres-operator.fullname" .) .Values.serviceAccount.name }}
32 | {{- end -}}
33 |
34 | {{/*
35 | Create a pod service account name.
36 | */}}
37 | {{- define "postgres-pod.serviceAccountName" -}}
38 | {{ default (printf "%s-%v" (include "postgres-operator.fullname" .) "pod") .Values.podServiceAccount.name }}
39 | {{- end -}}
40 |
41 | {{/*
42 | Create a pod priority class name.
43 | */}}
44 | {{- define "postgres-pod.priorityClassName" -}}
45 | {{ default (printf "%s-%v" (include "postgres-operator.fullname" .) "pod") .Values.podPriorityClassName.name }}
46 | {{- end -}}
47 |
48 | {{/*
49 | Create a controller ID.
50 | */}}
51 | {{- define "postgres-operator.controllerID" -}}
52 | {{ default (include "postgres-operator.fullname" .) .Values.controllerID.name }}
53 | {{- end -}}
54 |
55 | {{/*
56 | Create chart name and version as used by the chart label.
57 | */}}
58 | {{- define "postgres-operator.chart" -}}
59 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
60 | {{- end -}}
61 |
62 | {{/*
63 | Flatten nested config options when ConfigMap is used as ConfigTarget
64 | */}}
65 | {{- define "flattenValuesForConfigMap" }}
66 | {{- range $key, $value := . }}
67 | {{- if kindIs "slice" $value }}
68 | {{ $key }}: {{ join "," $value | quote }}
69 | {{- else if kindIs "map" $value }}
70 | {{- $list := list }}
71 | {{- range $subKey, $subValue := $value }}
72 | {{- $list = append $list (printf "%s:%s" $subKey $subValue) }}
73 | {{- end }}
74 | {{ $key }}: {{ join "," $list | quote }}
75 | {{- else }}
76 | {{ $key }}: {{ $value | quote }}
77 | {{- end }}
78 | {{- end }}
79 | {{- end }}
80 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/clusterrole-postgres-pod.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.rbac.create }}
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: {{ include "postgres-pod.serviceAccountName" . }}
6 | labels:
7 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
8 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
9 | app.kubernetes.io/managed-by: {{ .Release.Service }}
10 | app.kubernetes.io/instance: {{ .Release.Name }}
11 | rules:
12 | # Patroni needs to watch and manage config maps or endpoints
13 | {{- if toString .Values.configGeneral.kubernetes_use_configmaps | eq "true" }}
14 | - apiGroups:
15 | - ""
16 | resources:
17 | - configmaps
18 | verbs:
19 | - create
20 | - delete
21 | - deletecollection
22 | - get
23 | - list
24 | - patch
25 | - update
26 | - watch
27 | {{- else }}
28 | - apiGroups:
29 | - ""
30 | resources:
31 | - endpoints
32 | verbs:
33 | - create
34 | - delete
35 | - deletecollection
36 | - get
37 | - list
38 | - patch
39 | - update
40 | - watch
41 | {{- end }}
42 | # Patroni needs to watch pods
43 | - apiGroups:
44 | - ""
45 | resources:
46 | - pods
47 | verbs:
48 | - get
49 | - list
50 | - patch
51 | - update
52 | - watch
53 | # to let Patroni create a headless service
54 | - apiGroups:
55 | - ""
56 | resources:
57 | - services
58 | verbs:
59 | - create
60 | {{- if toString .Values.configKubernetes.spilo_privileged | eq "true" }}
61 | # to run privileged pods
62 | - apiGroups:
63 | - extensions
64 | resources:
65 | - podsecuritypolicies
66 | resourceNames:
67 | - privileged
68 | verbs:
69 | - use
70 | {{- end }}
71 | {{ end }}
72 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.rbac.create }}
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRoleBinding
4 | metadata:
5 | name: {{ include "postgres-operator.serviceAccountName" . }}
6 | labels:
7 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
8 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
9 | app.kubernetes.io/managed-by: {{ .Release.Service }}
10 | app.kubernetes.io/instance: {{ .Release.Name }}
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: {{ include "postgres-operator.serviceAccountName" . }}
15 | subjects:
16 | - kind: ServiceAccount
17 | name: {{ include "postgres-operator.serviceAccountName" . }}
18 | namespace: {{ .Release.Namespace }}
19 | {{ end }}
20 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | {{- if eq .Values.configTarget "ConfigMap" }}
2 | apiVersion: v1
3 | kind: ConfigMap
4 | metadata:
5 | name: {{ template "postgres-operator.fullname" . }}
6 | namespace: {{ .Release.Namespace }}
7 | labels:
8 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
9 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
10 | app.kubernetes.io/managed-by: {{ .Release.Service }}
11 | app.kubernetes.io/instance: {{ .Release.Name }}
12 | data:
13 | {{- if or .Values.podPriorityClassName.create .Values.podPriorityClassName.name }}
14 | pod_priority_class_name: {{ include "postgres-pod.priorityClassName" . }}
15 | {{- end }}
16 | pod_service_account_name: {{ include "postgres-pod.serviceAccountName" . }}
17 | {{- include "flattenValuesForConfigMap" .Values.configGeneral | indent 2 }}
18 | {{- include "flattenValuesForConfigMap" .Values.configUsers | indent 2 }}
19 | {{- include "flattenValuesForConfigMap" .Values.configMajorVersionUpgrade | indent 2 }}
20 | {{- include "flattenValuesForConfigMap" .Values.configKubernetes | indent 2 }}
21 | {{- include "flattenValuesForConfigMap" .Values.configTimeouts | indent 2 }}
22 | {{- include "flattenValuesForConfigMap" .Values.configLoadBalancer | indent 2 }}
23 | {{- include "flattenValuesForConfigMap" .Values.configAwsOrGcp | indent 2 }}
24 | {{- include "flattenValuesForConfigMap" .Values.configLogicalBackup | indent 2 }}
25 | {{- include "flattenValuesForConfigMap" .Values.configDebug | indent 2 }}
26 | {{- include "flattenValuesForConfigMap" .Values.configLoggingRestApi | indent 2 }}
27 | {{- include "flattenValuesForConfigMap" .Values.configTeamsApi | indent 2 }}
28 | {{- include "flattenValuesForConfigMap" .Values.configConnectionPooler | indent 2 }}
29 | {{- include "flattenValuesForConfigMap" .Values.configPatroni | indent 2 }}
30 | {{- end }}
31 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/operatorconfiguration.yaml:
--------------------------------------------------------------------------------
1 | {{- if eq .Values.configTarget "OperatorConfigurationCRD" }}
2 | apiVersion: "acid.zalan.do/v1"
3 | kind: OperatorConfiguration
4 | metadata:
5 | name: {{ template "postgres-operator.fullname" . }}
6 | namespace: {{ .Release.Namespace }}
7 | labels:
8 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
9 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
10 | app.kubernetes.io/managed-by: {{ .Release.Service }}
11 | app.kubernetes.io/instance: {{ .Release.Name }}
12 | configuration:
13 | {{ tpl (toYaml .Values.configGeneral) . | indent 2 }}
14 | users:
15 | {{ tpl (toYaml .Values.configUsers) . | indent 4 }}
16 | major_version_upgrade:
17 | {{ tpl (toYaml .Values.configMajorVersionUpgrade) . | indent 4 }}
18 | kubernetes:
19 | {{- if .Values.podPriorityClassName.name }}
20 | pod_priority_class_name: {{ .Values.podPriorityClassName.name }}
21 | {{- end }}
22 | pod_service_account_name: {{ include "postgres-pod.serviceAccountName" . }}
23 | oauth_token_secret_name: {{ template "postgres-operator.fullname" . }}
24 | {{ tpl (toYaml .Values.configKubernetes) . | indent 4 }}
25 | postgres_pod_resources:
26 | {{ tpl (toYaml .Values.configPostgresPodResources) . | indent 4 }}
27 | timeouts:
28 | {{ tpl (toYaml .Values.configTimeouts) . | indent 4 }}
29 | load_balancer:
30 | {{ tpl (toYaml .Values.configLoadBalancer) . | indent 4 }}
31 | aws_or_gcp:
32 | {{ tpl (toYaml .Values.configAwsOrGcp) . | indent 4 }}
33 | logical_backup:
34 | {{ tpl (toYaml .Values.configLogicalBackup) . | indent 4 }}
35 | debug:
36 | {{ tpl (toYaml .Values.configDebug) . | indent 4 }}
37 | teams_api:
38 | {{ tpl (toYaml .Values.configTeamsApi) . | indent 4 }}
39 | logging_rest_api:
40 | {{ tpl (toYaml .Values.configLoggingRestApi) . | indent 4 }}
41 | connection_pooler:
42 | {{ tpl (toYaml .Values.configConnectionPooler) . | indent 4 }}
43 | patroni:
44 | {{ tpl (toYaml .Values.configPatroni) . | indent 4 }}
45 | {{- end }}
46 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/postgres-pod-priority-class.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.podPriorityClassName.create }}
2 | apiVersion: scheduling.k8s.io/v1
3 | description: 'Use only for databases controlled by Postgres operator'
4 | kind: PriorityClass
5 | metadata:
6 | labels:
7 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
8 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
9 | app.kubernetes.io/managed-by: {{ .Release.Service }}
10 | app.kubernetes.io/instance: {{ .Release.Name }}
11 | name: {{ include "postgres-pod.priorityClassName" . }}
12 | namespace: {{ .Release.Namespace }}
13 | preemptionPolicy: PreemptLowerPriority
14 | globalDefault: false
15 | value: {{ .Values.podPriorityClassName.priority }}
16 | {{- end }}
17 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
6 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
7 | app.kubernetes.io/managed-by: {{ .Release.Service }}
8 | app.kubernetes.io/instance: {{ .Release.Name }}
9 | name: {{ template "postgres-operator.fullname" . }}
10 | namespace: {{ .Release.Namespace }}
11 | spec:
12 | type: ClusterIP
13 | ports:
14 | - port: 8080
15 | protocol: TCP
16 | targetPort: 8080
17 | selector:
18 | app.kubernetes.io/instance: {{ .Release.Name }}
19 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
20 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.serviceAccount.create }}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "postgres-operator.serviceAccountName" . }}
6 | namespace: {{ .Release.Namespace }}
7 | labels:
8 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
9 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
10 | app.kubernetes.io/managed-by: {{ .Release.Service }}
11 | app.kubernetes.io/instance: {{ .Release.Name }}
12 | {{ end }}
13 |
--------------------------------------------------------------------------------
/charts/postgres-operator/templates/user-facing-clusterroles.yaml:
--------------------------------------------------------------------------------
1 | {{ if .Values.rbac.createAggregateClusterRoles }}
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | rbac.authorization.k8s.io/aggregate-to-admin: "true"
7 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
8 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
9 | app.kubernetes.io/managed-by: {{ .Release.Service }}
10 | app.kubernetes.io/instance: {{ .Release.Name }}
11 | name: {{ template "postgres-operator.fullname" . }}:users:admin
12 | rules:
13 | - apiGroups:
14 | - acid.zalan.do
15 | resources:
16 | - postgresqls
17 | - postgresqls/status
18 | verbs:
19 | - create
20 | - delete
21 | - deletecollection
22 | - get
23 | - list
24 | - patch
25 | - update
26 | - watch
27 |
28 | ---
29 | apiVersion: rbac.authorization.k8s.io/v1
30 | kind: ClusterRole
31 | metadata:
32 | labels:
33 | rbac.authorization.k8s.io/aggregate-to-edit: "true"
34 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
35 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
36 | app.kubernetes.io/managed-by: {{ .Release.Service }}
37 | app.kubernetes.io/instance: {{ .Release.Name }}
38 | name: {{ template "postgres-operator.fullname" . }}:users:edit
39 | rules:
40 | - apiGroups:
41 | - acid.zalan.do
42 | resources:
43 | - postgresqls
44 | verbs:
45 | - create
46 | - update
47 | - patch
48 | - delete
49 |
50 | ---
51 | apiVersion: rbac.authorization.k8s.io/v1
52 | kind: ClusterRole
53 | metadata:
54 | labels:
55 | rbac.authorization.k8s.io/aggregate-to-view: "true"
56 | app.kubernetes.io/name: {{ template "postgres-operator.name" . }}
57 | helm.sh/chart: {{ template "postgres-operator.chart" . }}
58 | app.kubernetes.io/managed-by: {{ .Release.Service }}
59 | app.kubernetes.io/instance: {{ .Release.Name }}
60 | name: {{ template "postgres-operator.fullname" . }}:users:view
61 | rules:
62 | - apiGroups:
63 | - acid.zalan.do
64 | resources:
65 | - postgresqls
66 | - postgresqls/status
67 | verbs:
68 | - get
69 | - list
70 | - watch
71 | {{ end }}
72 |
--------------------------------------------------------------------------------
/cmd/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "os"
6 | "os/signal"
7 | "sync"
8 | "syscall"
9 | "time"
10 |
11 | log "github.com/sirupsen/logrus"
12 |
13 | "github.com/zalando/postgres-operator/pkg/controller"
14 | "github.com/zalando/postgres-operator/pkg/spec"
15 | "github.com/zalando/postgres-operator/pkg/util/k8sutil"
16 | )
17 |
18 | var (
19 | kubeConfigFile string
20 | outOfCluster bool
21 | version string
22 | config spec.ControllerConfig
23 | )
24 |
25 | func mustParseDuration(d string) time.Duration {
26 | duration, err := time.ParseDuration(d)
27 | if err != nil {
28 | panic(err)
29 | }
30 | return duration
31 | }
32 |
33 | func init() {
34 | flag.StringVar(&kubeConfigFile, "kubeconfig", "", "Path to kubeconfig file with authorization and master location information.")
35 | flag.BoolVar(&outOfCluster, "outofcluster", false, "Whether the operator runs in- our outside of the Kubernetes cluster.")
36 | flag.BoolVar(&config.NoDatabaseAccess, "nodatabaseaccess", false, "Disable all access to the database from the operator side.")
37 | flag.BoolVar(&config.NoTeamsAPI, "noteamsapi", false, "Disable all access to the teams API")
38 | flag.IntVar(&config.KubeQPS, "kubeqps", 10, "Kubernetes api requests per second.")
39 | flag.IntVar(&config.KubeBurst, "kubeburst", 20, "Kubernetes api requests burst limit.")
40 | flag.Parse()
41 |
42 | config.EnableJsonLogging = os.Getenv("ENABLE_JSON_LOGGING") == "true"
43 |
44 | configMapRawName := os.Getenv("CONFIG_MAP_NAME")
45 | if configMapRawName != "" {
46 |
47 | err := config.ConfigMapName.Decode(configMapRawName)
48 | if err != nil {
49 | log.Fatalf("incorrect config map name: %v", configMapRawName)
50 | }
51 |
52 | log.Printf("Fully qualified configmap name: %v", config.ConfigMapName)
53 |
54 | }
55 | if crdInterval := os.Getenv("CRD_READY_WAIT_INTERVAL"); crdInterval != "" {
56 | config.CRDReadyWaitInterval = mustParseDuration(crdInterval)
57 | } else {
58 | config.CRDReadyWaitInterval = 4 * time.Second
59 | }
60 |
61 | if crdTimeout := os.Getenv("CRD_READY_WAIT_TIMEOUT"); crdTimeout != "" {
62 | config.CRDReadyWaitTimeout = mustParseDuration(crdTimeout)
63 | } else {
64 | config.CRDReadyWaitTimeout = 30 * time.Second
65 | }
66 | }
67 |
68 | func main() {
69 | var err error
70 |
71 | if config.EnableJsonLogging {
72 | log.SetFormatter(&log.JSONFormatter{})
73 | }
74 | log.SetOutput(os.Stdout)
75 | log.Printf("Spilo operator %s\n", version)
76 |
77 | sigs := make(chan os.Signal, 1)
78 | stop := make(chan struct{})
79 | signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) // Push signals into channel
80 |
81 | wg := &sync.WaitGroup{} // Goroutines can add themselves to this to be waited on
82 |
83 | config.RestConfig, err = k8sutil.RestConfig(kubeConfigFile, outOfCluster)
84 | if err != nil {
85 | log.Fatalf("couldn't get REST config: %v", err)
86 | }
87 |
88 | config.RestConfig.QPS = float32(config.KubeQPS)
89 | config.RestConfig.Burst = config.KubeBurst
90 |
91 | c := controller.NewController(&config, "")
92 |
93 | c.Run(stop, wg)
94 |
95 | sig := <-sigs
96 | log.Printf("Shutting down... %+v", sig)
97 |
98 | close(stop) // Tell goroutines to stop themselves
99 | wg.Wait() // Wait for all to be stopped
100 | }
101 |
--------------------------------------------------------------------------------
/delivery.yaml:
--------------------------------------------------------------------------------
1 | version: "2017-09-20"
2 | pipeline:
3 | - id: build-postgres-operator
4 | type: script
5 | vm_config:
6 | type: linux
7 | size: large
8 | image: cdp-runtime/go
9 | cache:
10 | paths:
11 | - /go/pkg/mod # pkg cache for Go modules
12 | - ~/.cache/go-build # Go build cache
13 | commands:
14 | - desc: Run unit tests
15 | cmd: |
16 | make deps mocks test
17 |
18 | - desc: Build Docker image
19 | cmd: |
20 | IS_PR_BUILD=${CDP_PULL_REQUEST_NUMBER+"true"}
21 | if [[ ${CDP_TARGET_BRANCH} == "master" && ${IS_PR_BUILD} != "true" ]]
22 | then
23 | IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator
24 | else
25 | IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator-test
26 | fi
27 | export IMAGE
28 | make docker push
29 |
30 | - id: build-operator-ui
31 | type: script
32 | vm_config:
33 | type: linux
34 |
35 | commands:
36 | - desc: 'Prepare environment'
37 | cmd: |
38 | apt-get update
39 | apt-get install -y build-essential
40 |
41 | - desc: 'Compile JavaScript app'
42 | cmd: |
43 | cd ui
44 | make appjs
45 |
46 | - desc: 'Build and push Docker image'
47 | cmd: |
48 | cd ui
49 | IS_PR_BUILD=${CDP_PULL_REQUEST_NUMBER+"true"}
50 | if [[ ${CDP_TARGET_BRANCH} == "master" && ${IS_PR_BUILD} != "true" ]]
51 | then
52 | IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator-ui
53 | else
54 | IMAGE=registry-write.opensource.zalan.do/acid/postgres-operator-ui-test
55 | fi
56 | export IMAGE
57 | make docker
58 | make push
59 |
60 | - id: build-logical-backup
61 | type: script
62 | vm_config:
63 | type: linux
64 |
65 | commands:
66 | - desc: Build image
67 | cmd: |
68 | cd logical-backup
69 | export TAG=$(git describe --tags --always --dirty)
70 | IMAGE="registry-write.opensource.zalan.do/acid/logical-backup"
71 | docker build --rm -t "$IMAGE:$TAG$CDP_TAG" .
72 | docker push "$IMAGE:$TAG$CDP_TAG"
73 |
--------------------------------------------------------------------------------
/docker/DebugDockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.23-alpine
2 | LABEL maintainer="Team ACID @ Zalando <team-acid@zalando.de>"
3 |
4 | # We need root certificates to deal with teams api over https
5 | RUN apk -U add --no-cache ca-certificates delve
6 |
7 | COPY build/* /
8 |
9 | RUN addgroup -g 1000 pgo
10 | RUN adduser -D -u 1000 -G pgo -g 'Postgres Operator' pgo
11 |
12 | USER pgo:pgo
13 | RUN ls -l /
14 |
15 | CMD ["/dlv", "--listen=:7777", "--headless=true", "--api-version=2", "exec", "/postgres-operator"]
16 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG BASE_IMAGE=registry.opensource.zalan.do/library/alpine-3:latest
2 | FROM golang:1.23-alpine AS builder
3 | ARG VERSION=latest
4 |
5 | COPY . /go/src/github.com/zalando/postgres-operator
6 | WORKDIR /go/src/github.com/zalando/postgres-operator
7 |
8 | RUN GO111MODULE=on go mod vendor \
9 | && CGO_ENABLED=0 go build -o build/postgres-operator -v -ldflags "-X=main.version=${VERSION}" cmd/main.go
10 |
11 | FROM ${BASE_IMAGE}
12 | LABEL maintainer="Team ACID @ Zalando <team-acid@zalando.de>"
13 | LABEL org.opencontainers.image.source="https://github.com/zalando/postgres-operator"
14 |
15 | # We need root certificates to deal with teams api over https
16 | RUN apk -U upgrade --no-cache \
17 | && apk add --no-cache curl ca-certificates
18 |
19 | COPY --from=builder /go/src/github.com/zalando/postgres-operator/build/* /
20 |
21 | RUN addgroup -g 1000 pgo
22 | RUN adduser -D -u 1000 -G pgo -g 'Postgres Operator' pgo
23 |
24 | USER 1000:1000
25 |
26 | ENTRYPOINT ["/postgres-operator"]
27 |
--------------------------------------------------------------------------------
/docker/build_operator.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export DEBIAN_FRONTEND=noninteractive
4 |
5 | arch=$(dpkg --print-architecture)
6 |
7 | set -ex
8 |
9 | # Install dependencies
10 |
11 | apt-get update
12 | apt-get install -y wget
13 |
14 | (
15 | cd /tmp
16 | wget -q "https://storage.googleapis.com/golang/go1.23.4.linux-${arch}.tar.gz" -O go.tar.gz
17 | tar -xf go.tar.gz
18 | mv go /usr/local
19 | ln -s /usr/local/go/bin/go /usr/bin/go
20 | go version
21 | )
22 |
23 | # Build
24 |
25 | export PATH="$PATH:$HOME/go/bin"
26 | export GOPATH="$HOME/go"
27 | mkdir -p build
28 |
29 | GO111MODULE=on go mod vendor
30 | CGO_ENABLED=0 go build -o build/postgres-operator -v -ldflags "$OPERATOR_LDFLAGS" cmd/main.go
31 |
--------------------------------------------------------------------------------
/docs/diagrams/Makefile:
--------------------------------------------------------------------------------
1 | OBJ=$(patsubst %.tex, %.png, $(wildcard *.tex))
2 |
3 | .PHONY: all
4 |
5 | all: $(OBJ)
6 |
7 | %.pdf: %.tex
8 | lualatex lt; -shell-escape $@
9 |
10 | %.png: %.pdf
11 | convert -flatten -density 300 lt; -quality 90 $@
12 |
--------------------------------------------------------------------------------
/docs/diagrams/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/logo.png
--------------------------------------------------------------------------------
/docs/diagrams/neutral_operator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/neutral_operator.png
--------------------------------------------------------------------------------
/docs/diagrams/neutral_operator_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/neutral_operator_dark.png
--------------------------------------------------------------------------------
/docs/diagrams/neutral_operator_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/neutral_operator_light.png
--------------------------------------------------------------------------------
/docs/diagrams/operator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/operator.png
--------------------------------------------------------------------------------
/docs/diagrams/pgui-cluster-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/pgui-cluster-list.png
--------------------------------------------------------------------------------
/docs/diagrams/pgui-cluster-startup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/pgui-cluster-startup.png
--------------------------------------------------------------------------------
/docs/diagrams/pgui-delete-cluster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/pgui-delete-cluster.png
--------------------------------------------------------------------------------
/docs/diagrams/pgui-finished-setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/pgui-finished-setup.png
--------------------------------------------------------------------------------
/docs/diagrams/pgui-new-cluster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/pgui-new-cluster.png
--------------------------------------------------------------------------------
/docs/diagrams/pgui-operator-logs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/pgui-operator-logs.png
--------------------------------------------------------------------------------
/docs/diagrams/pgui-waiting-for-master.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/pgui-waiting-for-master.png
--------------------------------------------------------------------------------
/docs/diagrams/pod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/docs/diagrams/pod.png
--------------------------------------------------------------------------------
/docs/reference/command_line_and_environment.md:
--------------------------------------------------------------------------------
1 | # Command-line options
2 |
3 | The following command-line options are supported for the operator:
4 |
5 | * **-kubeconfig**
6 | the path to the kubeconfig file. Usually named config, it contains
7 | authorization information as well as the URL of the Kubernetes master.
8 |
9 | * **-outofcluster**
10 | run the operator on a client machine, as opposed to a within the cluster.
11 | When running in this mode, the operator cannot connect to databases inside
12 | the cluster, as well as call URLs of in-cluster objects (i.e. teams api
13 | server). Mostly useful for debugging, it also requires setting the
14 | `OPERATOR_NAMESPACE` environment variable for the operator own namespace.
15 |
16 | * **-nodatabaseaccess**
17 | disable database access from the operator. Equivalent to the
18 | `enable_database_access` set to off and can be overridden by the
19 | aforementioned operator configuration option.
20 |
21 | * **-noteamsapi**
22 | disable access to the teams API. Equivalent to the `enable_teams_api` set to
23 | off can can be overridden by the aforementioned operator configuration
24 | option.
25 |
26 | In addition to that, standard [glog
27 | flags](https://godoc.org/github.com/golang/glog) are also supported. For
28 | instance, one may want to add `-alsologtostderr` and `-v=8` to debug the
29 | operator REST calls.
30 |
31 | # Environment variables
32 |
33 | The following environment variables are accepted by the operator:
34 |
35 | * **CONFIG_MAP_NAME**
36 | name of the config map where the operator should look for its configuration.
37 | Must be present.
38 |
39 | * **OPERATOR_NAMESPACE**
40 | name of the namespace the operator runs it. Overrides autodetection by the
41 | operator itself.
42 |
43 | * **WATCHED_NAMESPACE**
44 | the name of the namespace the operator watches. Special '*' character denotes
45 | all namespaces. Empty value defaults to the operator namespace. Overrides the
46 | `watched_namespace` operator parameter.
47 |
48 | * **SCALYR_API_KEY** (*deprecated*)
49 | the value of the Scalyr API key to supply to the pods. Overrides the
50 | `scalyr_api_key` operator parameter.
51 |
52 | * **CRD_READY_WAIT_TIMEOUT**
53 | defines the timeout for the complete `postgresql` CRD creation. When not set
54 | default is 30s.
55 |
56 | * **CRD_READY_WAIT_INTERVAL**
57 | defines the interval between consecutive attempts waiting for the
58 | `postgresql` CRD to be created. The default is 5s.
59 |
60 | * **ENABLE_JSON_LOGGING**
61 | Set to `true` for JSON formatted logging output.
62 | The default is false.
63 |
--------------------------------------------------------------------------------
/e2e/Dockerfile:
--------------------------------------------------------------------------------
1 | # An image to run e2e tests.
2 | # The image does not include the tests; all necessary files are bind-mounted when a container starts.
3 | FROM ubuntu:20.04
4 | LABEL maintainer="Team ACID @ Zalando <team-acid@zalando.de>"
5 |
6 | ENV TERM xterm-256color
7 |
8 | COPY requirements.txt ./
9 |
10 | RUN apt-get update \
11 | && apt-get install --no-install-recommends -y \
12 | python3 \
13 | python3-setuptools \
14 | python3-pip \
15 | curl \
16 | vim \
17 | && pip3 install --no-cache-dir -r requirements.txt \
18 | && curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.24.3/bin/linux/amd64/kubectl \
19 | && chmod +x ./kubectl \
20 | && mv ./kubectl /usr/local/bin/kubectl \
21 | && apt-get clean \
22 | && rm -rf /var/lib/apt/lists/*
23 |
24 | # working line
25 | # python3 -m unittest discover -v --failfast -k test_e2e.EndToEndTestCase.test_lazy_spilo_upgrade --start-directory tests
26 | ENTRYPOINT ["python3", "-m", "unittest"]
27 | CMD ["discover","-v","--failfast","--start-directory","/tests"]
--------------------------------------------------------------------------------
/e2e/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: clean copy docker push tools test
2 |
3 | BINARY ?= postgres-operator-e2e-tests-runner
4 | BUILD_FLAGS ?= -v
5 | CGO_ENABLED ?= 0
6 | ifeq ($(RACE),1)
7 | BUILD_FLAGS += -race -a
8 | CGO_ENABLED=1
9 | endif
10 |
11 | LOCAL_BUILD_FLAGS ?= $(BUILD_FLAGS)
12 | LDFLAGS ?= -X=main.version=$(VERSION)
13 |
14 | IMAGE ?= registry.opensource.zalan.do/acid/$(BINARY)
15 | VERSION ?= $(shell git describe --tags --always --dirty)
16 | TAG ?= $(VERSION)
17 | GITHEAD = $(shell git rev-parse --short HEAD)
18 | GITURL = $(shell git config --get remote.origin.url)
19 | GITSTATU = $(shell git status --porcelain || echo 'no changes')
20 | TTYFLAGS = $(shell test -t 0 && echo '-it')
21 |
22 | ifndef GOPATH
23 | GOPATH := $(HOME)/go
24 | endif
25 |
26 | PATH := $(GOPATH)/bin:$(PATH)
27 |
28 | default: tools
29 |
30 | clean:
31 | rm -rf manifests
32 | rm -rf tls
33 |
34 | copy: clean
35 | mkdir manifests
36 | cp -r ../manifests .
37 | mkdir tls
38 |
39 | docker:
40 | docker build -t "$(IMAGE):$(TAG)" .
41 |
42 | push: docker
43 | docker push "$(IMAGE):$(TAG)"
44 |
45 | tools:
46 | # install pinned version of 'kind'
47 | # go install must run outside of a dir with a (module-based) Go project !
48 | # otherwise go install updates project's dependencies and/or behaves differently
49 | cd "/tmp" && GO111MODULE=on go install sigs.k8s.io/kind@v0.24.0
50 |
51 | e2etest: tools copy clean
52 | ./run.sh main
53 |
54 | cleanup: clean
55 | ./run.sh cleanup
--------------------------------------------------------------------------------
/e2e/exec.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | kubectl exec -i $1 -- sh -c "$2"
3 |
--------------------------------------------------------------------------------
/e2e/exec_into_env.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export cluster_name="postgres-operator-e2e-tests"
4 | export kubeconfig_path="/tmp/kind-config-${cluster_name}"
5 | export operator_image="registry.opensource.zalan.do/acid/postgres-operator:latest"
6 | export e2e_test_runner_image="registry.opensource.zalan.do/acid/postgres-operator-e2e-tests-runner:0.4"
7 |
8 | docker run -it --entrypoint /bin/bash --network=host -e "TERM=xterm-256color" \
9 | --mount type=bind,source="$(readlink -f ${kubeconfig_path})",target=/root/.kube/config \
10 | --mount type=bind,source="$(readlink -f manifests)",target=/manifests \
11 | --mount type=bind,source="$(readlink -f tests)",target=/tests \
12 | --mount type=bind,source="$(readlink -f exec.sh)",target=/exec.sh \
13 | --mount type=bind,source="$(readlink -f scripts)",target=/scripts \
14 | -e OPERATOR_IMAGE="${operator_image}" "${e2e_test_runner_image}"
15 |
--------------------------------------------------------------------------------
/e2e/kind-cluster-postgres-operator-e2e-tests.yaml:
--------------------------------------------------------------------------------
1 | kind: Cluster
2 | apiVersion: kind.x-k8s.io/v1alpha4
3 | nodes:
4 | - role: control-plane
5 | - role: worker
6 | - role: worker
7 | featureGates:
8 | StatefulSetAutoDeletePVC: true
9 |
--------------------------------------------------------------------------------
/e2e/requirements.txt:
--------------------------------------------------------------------------------
1 | kubernetes==29.2.0
2 | timeout_decorator==0.5.0
3 | pyyaml==6.0.1
4 |
--------------------------------------------------------------------------------
/e2e/scripts/cleanup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | kubectl delete postgresql acid-minimal-cluster
3 | kubectl delete deployments -l application=db-connection-pooler,cluster-name=acid-minimal-cluster
4 | kubectl delete statefulsets -l application=spilo,cluster-name=acid-minimal-cluster
5 | kubectl delete services -l application=spilo,cluster-name=acid-minimal-cluster
6 | kubectl delete configmap postgres-operator
7 | kubectl delete deployment postgres-operator
--------------------------------------------------------------------------------
/e2e/scripts/get_logs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | kubectl logs $(kubectl get pods -l name=postgres-operator --field-selector status.phase=Running -o jsonpath='{.items..metadata.name}')
3 |
--------------------------------------------------------------------------------
/e2e/scripts/watch_objects.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | watch -c "
4 | kubectl get postgresql --all-namespaces
5 | echo
6 | echo -n 'Rolling upgrade pending: '
7 | kubectl get pods -o jsonpath='{.items[].metadata.annotations.zalando-postgres-operator-rolling-update-required}'
8 | echo
9 | echo
10 | echo 'Pods'
11 | kubectl get pods -l application=spilo -o wide --all-namespaces
12 | echo
13 | kubectl get pods -l application=db-connection-pooler -o wide --all-namespaces
14 | echo
15 | echo 'Statefulsets'
16 | kubectl get statefulsets --all-namespaces
17 | echo
18 | echo 'Deployments'
19 | kubectl get deployments --all-namespaces -l application=db-connection-pooler
20 | kubectl get deployments --all-namespaces -l application=postgres-operator
21 | echo
22 | echo
23 | echo 'Step from operator deployment'
24 | kubectl get pods -l name=postgres-operator -o jsonpath='{.items..metadata.annotations.step}'
25 | echo
26 | echo
27 | echo 'Spilo Image in statefulset'
28 | kubectl get pods -l application=spilo -o jsonpath='{.items..spec.containers..image}'
29 | echo
30 | echo
31 | echo 'Queue Status'
32 | kubectl exec -it \$(kubectl get pods -l name=postgres-operator -o jsonpath='{.items..metadata.name}') -- curl localhost:8080/workers/all/status/
33 | echo"
--------------------------------------------------------------------------------
/e2e/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # This version is replaced during release process.
2 | __version__ = '2019.0.dev1'
3 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/zalando/postgres-operator
2 |
3 | go 1.23.4
4 |
5 | require (
6 | github.com/aws/aws-sdk-go v1.53.8
7 | github.com/golang/mock v1.6.0
8 | github.com/lib/pq v1.10.9
9 | github.com/motomux/pretty v0.0.0-20161209205251-b2aad2c9a95d
10 | github.com/pkg/errors v0.9.1
11 | github.com/r3labs/diff v1.1.0
12 | github.com/sirupsen/logrus v1.9.3
13 | github.com/stretchr/testify v1.9.0
14 | golang.org/x/crypto v0.31.0
15 | golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3
16 | gopkg.in/yaml.v2 v2.4.0
17 | k8s.io/api v0.30.4
18 | k8s.io/apiextensions-apiserver v0.25.9
19 | k8s.io/apimachinery v0.30.4
20 | k8s.io/client-go v0.30.4
21 | k8s.io/code-generator v0.25.9
22 | )
23 |
24 | require (
25 | github.com/Masterminds/semver v1.5.0
26 | github.com/davecgh/go-spew v1.1.1 // indirect
27 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect
28 | github.com/evanphx/json-patch v4.12.0+incompatible // indirect
29 | github.com/go-logr/logr v1.4.1 // indirect
30 | github.com/go-openapi/jsonpointer v0.19.6 // indirect
31 | github.com/go-openapi/jsonreference v0.20.2 // indirect
32 | github.com/go-openapi/swag v0.22.3 // indirect
33 | github.com/gogo/protobuf v1.3.2 // indirect
34 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
35 | github.com/golang/protobuf v1.5.4 // indirect
36 | github.com/google/gnostic-models v0.6.8 // indirect
37 | github.com/google/go-cmp v0.6.0 // indirect
38 | github.com/google/gofuzz v1.2.0 // indirect
39 | github.com/google/uuid v1.3.0 // indirect
40 | github.com/gorilla/websocket v1.5.0 // indirect
41 | github.com/imdario/mergo v0.3.6 // indirect
42 | github.com/jmespath/go-jmespath v0.4.0 // indirect
43 | github.com/josharian/intern v1.0.0 // indirect
44 | github.com/json-iterator/go v1.1.12 // indirect
45 | github.com/kr/text v0.2.0 // indirect
46 | github.com/mailru/easyjson v0.7.7 // indirect
47 | github.com/moby/spdystream v0.2.0 // indirect
48 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
49 | github.com/modern-go/reflect2 v1.0.2 // indirect
50 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
51 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
52 | github.com/pmezard/go-difflib v1.0.0 // indirect
53 | github.com/spf13/pflag v1.0.5 // indirect
54 | golang.org/x/mod v0.17.0 // indirect
55 | golang.org/x/net v0.25.0 // indirect
56 | golang.org/x/oauth2 v0.10.0 // indirect
57 | golang.org/x/sync v0.10.0 // indirect
58 | golang.org/x/sys v0.28.0 // indirect
59 | golang.org/x/term v0.27.0 // indirect
60 | golang.org/x/text v0.21.0 // indirect
61 | golang.org/x/time v0.3.0 // indirect
62 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
63 | google.golang.org/appengine v1.6.7 // indirect
64 | google.golang.org/protobuf v1.33.0 // indirect
65 | gopkg.in/inf.v0 v0.9.1 // indirect
66 | gopkg.in/yaml.v3 v3.0.1 // indirect
67 | k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect
68 | k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 // indirect
69 | k8s.io/klog/v2 v2.120.1 // indirect
70 | k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
71 | k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
72 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
73 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
74 | sigs.k8s.io/yaml v1.3.0 // indirect
75 | )
76 |
--------------------------------------------------------------------------------
/hack/custom-boilerplate.go.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright YEAR Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
--------------------------------------------------------------------------------
/hack/tools.go:
--------------------------------------------------------------------------------
1 | // +build tools
2 |
3 | /*
4 | Copyright 2019 The Kubernetes Authors.
5 | Licensed under the Apache License, Version 2.0 (the "License");
6 | you may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 | http://www.apache.org/licenses/LICENSE-2.0
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | */
15 |
16 | // This package imports things required by build scripts, to force `go mod` to see them as dependencies
17 | package tools
18 |
19 | import _ "k8s.io/code-generator"
20 |
--------------------------------------------------------------------------------
/hack/update-codegen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o errexit
4 | set -o nounset
5 | set -o pipefail
6 |
7 | GENERATED_PACKAGE_ROOT="github.com"
8 | OPERATOR_PACKAGE_ROOT="${GENERATED_PACKAGE_ROOT}/zalando/postgres-operator"
9 | SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/..
10 | TARGET_CODE_DIR=${1-${SCRIPT_ROOT}/pkg}
11 | 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)}
12 |
13 | cleanup() {
14 | rm -rf "${GENERATED_PACKAGE_ROOT}"
15 | }
16 | trap "cleanup" EXIT SIGINT
17 |
18 | bash "${CODEGEN_PKG}/generate-groups.sh" client,deepcopy,informer,lister \
19 | "${OPERATOR_PACKAGE_ROOT}/pkg/generated" "${OPERATOR_PACKAGE_ROOT}/pkg/apis" \
20 | "acid.zalan.do:v1 zalando.org:v1" \
21 | --go-header-file "${SCRIPT_ROOT}"/hack/custom-boilerplate.go.txt \
22 | -o ./
23 |
24 | cp -r "${OPERATOR_PACKAGE_ROOT}"/pkg/* "${TARGET_CODE_DIR}"
25 |
26 | cleanup
27 |
--------------------------------------------------------------------------------
/hack/verify-codegen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o errexit
4 | set -o nounset
5 | set -o pipefail
6 |
7 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/..
8 | DIFFROOT="${SCRIPT_ROOT}/pkg"
9 | TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg"
10 | _tmp="${SCRIPT_ROOT}/_tmp"
11 |
12 | cleanup() {
13 | rm -rf "${_tmp}"
14 | }
15 | trap "cleanup" EXIT SIGINT
16 |
17 | cleanup
18 |
19 | mkdir -p "${TMP_DIFFROOT}"
20 | cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
21 |
22 | "${SCRIPT_ROOT}/hack/update-codegen.sh" "${TMP_DIFFROOT}"
23 | echo "diffing ${DIFFROOT} against freshly generated codegen"
24 | ret=0
25 | diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
26 | if [[ $ret -eq 0 ]]
27 | then
28 | echo "${DIFFROOT} up to date."
29 | else
30 | echo "${DIFFROOT} is out of date. Please run 'make codegen'"
31 | exit 1
32 | fi
33 |
--------------------------------------------------------------------------------
/kubectl-pg/build.sh:
--------------------------------------------------------------------------------
1 |
2 | VERSION=1.0
3 | sed -i "s/KubectlPgVersion string = \"[^\"]*\"/KubectlPgVersion string = \"${VERSION}\"/" cmd/version.go
4 | go install
--------------------------------------------------------------------------------
/kubectl-pg/cmd/check.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "context"
27 | "fmt"
28 | "log"
29 |
30 | "github.com/spf13/cobra"
31 | postgresConstants "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
32 | v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
33 | apiextv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
34 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35 | )
36 |
37 | // checkCmd represent kubectl pg check.
38 | var checkCmd = &cobra.Command{
39 | Use: "check",
40 | Short: "Checks the Postgres operator is installed in the k8s cluster",
41 | Long: `Checks that the Postgres CRD is registered in a k8s cluster.
42 | This means that the operator pod was able to start normally.`,
43 | Run: func(cmd *cobra.Command, args []string) {
44 | check()
45 | },
46 | Example: `
47 | kubectl pg check
48 | `,
49 | }
50 |
51 | // check validates postgresql CRD registered or not.
52 | func check() *v1.CustomResourceDefinition {
53 | config := getConfig()
54 | apiExtClient, err := apiextv1.NewForConfig(config)
55 | if err != nil {
56 | log.Fatal(err)
57 | }
58 |
59 | crdInfo, err := apiExtClient.CustomResourceDefinitions().Get(context.TODO(), postgresConstants.PostgresCRDResouceName, metav1.GetOptions{})
60 | if err != nil {
61 | log.Fatal(err)
62 | }
63 |
64 | if crdInfo.Name == postgresConstants.PostgresCRDResouceName {
65 | fmt.Printf("Postgres Operator is installed in the k8s cluster.\n")
66 | } else {
67 | fmt.Printf("Postgres Operator is not installed in the k8s cluster.\n")
68 | }
69 | return crdInfo
70 | }
71 |
72 | func init() {
73 | rootCmd.AddCommand(checkCmd)
74 | }
75 |
--------------------------------------------------------------------------------
/kubectl-pg/cmd/create.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "context"
27 | "fmt"
28 | "log"
29 | "os"
30 |
31 | "github.com/spf13/cobra"
32 | v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
33 | PostgresqlLister "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
34 | "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme"
35 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
36 | )
37 |
38 | // createCmd kubectl pg create.
39 | var createCmd = &cobra.Command{
40 | Use: "create",
41 | Short: "Creates postgres object using manifest file",
42 | Long: `Creates postgres custom resource objects from a manifest file.`,
43 | Run: func(cmd *cobra.Command, args []string) {
44 | fileName, _ := cmd.Flags().GetString("file")
45 | create(fileName)
46 | },
47 | Example: `
48 | kubectl pg create -f cluster-manifest.yaml
49 | `,
50 | }
51 |
52 | // Create postgresql resources.
53 | func create(fileName string) {
54 | config := getConfig()
55 | postgresConfig, err := PostgresqlLister.NewForConfig(config)
56 | if err != nil {
57 | log.Fatal(err)
58 | }
59 | ymlFile, err := os.ReadFile(fileName)
60 | if err != nil {
61 | log.Fatal(err)
62 | }
63 |
64 | decode := scheme.Codecs.UniversalDeserializer().Decode
65 | obj, _, err := decode([]byte(ymlFile), nil, &v1.Postgresql{})
66 | if err != nil {
67 | log.Fatal(err)
68 | }
69 |
70 | postgresSql := obj.(*v1.Postgresql)
71 | _, err = postgresConfig.Postgresqls(postgresSql.Namespace).Create(context.TODO(), postgresSql, metav1.CreateOptions{})
72 | if err != nil {
73 | log.Fatal(err)
74 | }
75 |
76 | fmt.Printf("postgresql %s created.\n", postgresSql.Name)
77 | }
78 |
79 | func init() {
80 | createCmd.Flags().StringP("file", "f", "", "manifest file with the cluster definition.")
81 | rootCmd.AddCommand(createCmd)
82 | }
83 |
--------------------------------------------------------------------------------
/kubectl-pg/cmd/root.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "fmt"
27 | "os"
28 |
29 | "github.com/spf13/cobra"
30 | "github.com/spf13/viper"
31 | )
32 |
33 | var rootCmd = &cobra.Command{
34 | Use: "kubectl-pg",
35 | Short: "kubectl plugin for the Zalando Postgres operator.",
36 | Long: `kubectl pg plugin for interaction with Zalando postgres operator.`,
37 | }
38 |
39 | // Execute adds all child commands to the root command and sets flags appropriately.
40 | // This is called by main.main(). It only needs to happen once to the rootCmd.
41 | func Execute() {
42 | if err := rootCmd.Execute(); err != nil {
43 | fmt.Println(err)
44 | os.Exit(1)
45 | }
46 | }
47 |
48 | func init() {
49 | viper.SetDefault("author", "Vineeth Pothulapati <vineethpothulapati@outlook.com>")
50 | viper.SetDefault("license", "mit")
51 | }
52 |
--------------------------------------------------------------------------------
/kubectl-pg/cmd/version.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | package cmd
24 |
25 | import (
26 | "fmt"
27 | "log"
28 | "strings"
29 |
30 | "github.com/spf13/cobra"
31 | "k8s.io/client-go/kubernetes"
32 | )
33 |
34 | var KubectlPgVersion string = "1.0"
35 |
36 | // versionCmd represents the version command
37 | var versionCmd = &cobra.Command{
38 | Use: "version",
39 | Short: "version of kubectl-pg & postgres-operator",
40 | Long: `version of kubectl-pg and current running postgres-operator`,
41 | Run: func(cmd *cobra.Command, args []string) {
42 | namespace, err := cmd.Flags().GetString("namespace")
43 | if err != nil {
44 | log.Fatal(err)
45 | }
46 | version(namespace)
47 | },
48 | Example: `
49 | #Lists the version of kubectl pg plugin and postgres operator in current namespace
50 | kubectl pg version
51 |
52 | #Lists the version of kubectl pg plugin and postgres operator in provided namespace
53 | kubectl pg version -n namespace01
54 | `,
55 | }
56 |
57 | func version(namespace string) {
58 | fmt.Printf("kubectl-pg: %s\n", KubectlPgVersion)
59 |
60 | config := getConfig()
61 | client, err := kubernetes.NewForConfig(config)
62 | if err != nil {
63 | log.Fatal(err)
64 | }
65 |
66 | operatorDeployment := getPostgresOperator(client)
67 | if operatorDeployment.Name == "" {
68 | log.Fatal("make sure zalando's postgres operator is running")
69 | }
70 | operatorImage := operatorDeployment.Spec.Template.Spec.Containers[0].Image
71 | imageDetails := strings.Split(operatorImage, ":")
72 | imageSplit := len(imageDetails)
73 | imageVersion := imageDetails[imageSplit-1]
74 | fmt.Printf("Postgres-Operator: %s\n", imageVersion)
75 | }
76 |
77 | func init() {
78 | rootCmd.AddCommand(versionCmd)
79 | versionCmd.Flags().StringP("namespace", "n", DefaultNamespace, "provide the namespace.")
80 | }
81 |
--------------------------------------------------------------------------------
/kubectl-pg/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2019 Vineeth Pothulapati <vineethpothulapati@outlook.com>
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | package main
24 |
25 | import (
26 | "github.com/zalando/postgres-operator/kubectl-pg/cmd"
27 | )
28 |
29 | func main() {
30 | cmd.Execute()
31 | }
32 |
--------------------------------------------------------------------------------
/logical-backup/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG BASE_IMAGE=registry.opensource.zalan.do/library/ubuntu-22.04:latest
2 | FROM ${BASE_IMAGE}
3 | LABEL maintainer="Team ACID @ Zalando <team-acid@zalando.de>"
4 |
5 | SHELL ["/bin/bash", "-o", "pipefail", "-c"]
6 | RUN apt-get update \
7 | && apt-get install --no-install-recommends -y \
8 | apt-utils \
9 | ca-certificates \
10 | lsb-release \
11 | pigz \
12 | python3-pip \
13 | python3-setuptools \
14 | curl \
15 | jq \
16 | gnupg \
17 | gcc \
18 | libffi-dev \
19 | && curl -sL https://aka.ms/InstallAzureCLIDeb | bash \
20 | && pip3 install --upgrade pip \
21 | && pip3 install --no-cache-dir awscli --upgrade \
22 | && pip3 install --no-cache-dir gsutil --upgrade \
23 | && echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
24 | && cat /etc/apt/sources.list.d/pgdg.list \
25 | && curl --silent https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
26 | && apt-get update \
27 | && apt-get install --no-install-recommends -y \
28 | postgresql-client-17 \
29 | postgresql-client-16 \
30 | postgresql-client-15 \
31 | postgresql-client-14 \
32 | postgresql-client-13 \
33 | && apt-get clean \
34 | && rm -rf /var/lib/apt/lists/*
35 |
36 | COPY dump.sh ./
37 |
38 | ENV PG_DIR=/usr/lib/postgresql
39 |
40 | ENTRYPOINT ["/dump.sh"]
41 |
--------------------------------------------------------------------------------
/manifests/api-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: postgres-operator
5 | spec:
6 | type: ClusterIP
7 | ports:
8 | - port: 8080
9 | protocol: TCP
10 | targetPort: 8080
11 | selector:
12 | name: postgres-operator
13 |
--------------------------------------------------------------------------------
/manifests/custom-team-membership.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "acid.zalan.do/v1"
2 | kind: PostgresTeam
3 | metadata:
4 | name: custom-team-membership
5 | spec:
6 | additionalSuperuserTeams:
7 | acid:
8 | - "postgres_superusers"
9 | additionalTeams:
10 | acid: []
11 | additionalMembers:
12 | acid:
13 | - "elephant"
14 |
--------------------------------------------------------------------------------
/manifests/e2e-storage-class.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: storage.k8s.io/v1
2 | kind: StorageClass
3 | metadata:
4 | name: standard
5 | annotations:
6 | storageclass.kubernetes.io/is-default-class: "true"
7 | provisioner: kubernetes.io/host-path
8 |
--------------------------------------------------------------------------------
/manifests/fake-teams-api.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: fake-teams-api
5 | spec:
6 | replicas: 1
7 | selector:
8 | matchLabels:
9 | name: fake-teams-api
10 | template:
11 | metadata:
12 | labels:
13 | name: fake-teams-api
14 | spec:
15 | containers:
16 | - name: fake-teams-api
17 | image: ikitiki/fake-teams-api:latest
18 |
19 | ---
20 |
21 | apiVersion: v1
22 | kind: Service
23 | metadata:
24 | name: fake-teams-api
25 | spec:
26 | selector:
27 | name: fake-teams-api
28 | ports:
29 | - name: server
30 | port: 80
31 | protocol: TCP
32 | targetPort: 80
33 | type: NodePort
34 |
35 | ---
36 |
37 | apiVersion: v1
38 | kind: Secret
39 | metadata:
40 | name: postgresql-operator
41 | namespace: default
42 | type: Opaque
43 | data:
44 | read-only-token-secret: dGVzdHRva2Vu
45 | read-only-token-type: QmVhcmVy
46 |
--------------------------------------------------------------------------------
/manifests/fes.crd.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apiextensions.k8s.io/v1
2 | kind: CustomResourceDefinition
3 | metadata:
4 | name: fabriceventstreams.zalando.org
5 | spec:
6 | group: zalando.org
7 | names:
8 | kind: FabricEventStream
9 | listKind: FabricEventStreamList
10 | plural: fabriceventstreams
11 | singular: fabriceventstream
12 | shortNames:
13 | - fes
14 | categories:
15 | - all
16 | scope: Namespaced
17 | versions:
18 | - name: v1
19 | served: true
20 | storage: true
21 | schema:
22 | openAPIV3Schema:
23 | type: object
24 |
--------------------------------------------------------------------------------
/manifests/infrastructure-roles-configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: postgresql-infrastructure-roles
5 | data:
6 | batman: |
7 | inrole: [admin] # following roles will be assigned to the new user
8 | user_flags:
9 | - createdb
10 | db_parameters: # db parameters, applyed for this particular user
11 | log_statement: all
12 |
--------------------------------------------------------------------------------
/manifests/infrastructure-roles-new.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | data:
3 | # infrastructure role definition in the new format
4 | # robot_zmon_acid_monitoring_new
5 | user: cm9ib3Rfem1vbl9hY2lkX21vbml0b3JpbmdfbmV3
6 | # foobar_new
7 | password: Zm9vYmFyX25ldw==
8 | kind: Secret
9 | metadata:
10 | name: postgresql-infrastructure-roles-new
11 | type: Opaque
12 |
--------------------------------------------------------------------------------
/manifests/infrastructure-roles.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | data:
3 | # required format (w/o quotes): 'propertyNumber: value'
4 | # allowed properties: 'user', 'password', 'inrole'
5 | # numbers >= 1 are mandatory
6 | # alternatively, supply the user: password pairs and
7 | # provide other options in the configmap.
8 | # robot_zmon_acid_monitoring
9 | user1: cm9ib3Rfem1vbl9hY2lkX21vbml0b3Jpbmc=
10 | # foobar
11 | password1: Zm9vYmFy
12 | # robot_zmon
13 | inrole1: cm9ib3Rfem1vbg==
14 | # testuser
15 | user2: dGVzdHVzZXI=
16 | # testpassword
17 | password2: dGVzdHBhc3N3b3Jk
18 | # user batman with the password justice
19 | # look for other fields in the infrastructure roles configmap
20 | batman: anVzdGljZQ==
21 | kind: Secret
22 | metadata:
23 | name: postgresql-infrastructure-roles
24 | type: Opaque
25 |
--------------------------------------------------------------------------------
/manifests/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | - configmap.yaml
5 | - operator-service-account-rbac.yaml
6 | - postgres-operator.yaml
7 | - api-service.yaml
8 |
--------------------------------------------------------------------------------
/manifests/minimal-fake-pooler-deployment.yaml:
--------------------------------------------------------------------------------
1 | # will not run but is good enough for tests to fail
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: acid-minimal-cluster-pooler
6 | labels:
7 | application: db-connection-pooler
8 | connection-pooler: acid-minimal-cluster-pooler
9 | spec:
10 | replicas: 1
11 | selector:
12 | matchLabels:
13 | application: db-connection-pooler
14 | connection-pooler: acid-minimal-cluster-pooler
15 | cluster-name: acid-minimal-cluster
16 | template:
17 | metadata:
18 | labels:
19 | application: db-connection-pooler
20 | connection-pooler: acid-minimal-cluster-pooler
21 | cluster-name: acid-minimal-cluster
22 | spec:
23 | serviceAccountName: postgres-operator
24 | containers:
25 | - name: postgres-operator
26 | image: registry.opensource.zalan.do/acid/pgbouncer:master-32
27 | imagePullPolicy: IfNotPresent
28 | resources:
29 | requests:
30 | cpu: 100m
31 | memory: 250Mi
32 | limits:
33 | cpu: 500m
34 | memory: 500Mi
35 | env: []
36 |
--------------------------------------------------------------------------------
/manifests/minimal-postgres-lowest-version-manifest.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "acid.zalan.do/v1"
2 | kind: postgresql
3 | metadata:
4 | name: acid-upgrade-test
5 | spec:
6 | teamId: "acid"
7 | volume:
8 | size: 1Gi
9 | numberOfInstances: 2
10 | users:
11 | zalando: # database owner
12 | - superuser
13 | - createdb
14 | foo_user: [] # role for application foo
15 | databases:
16 | foo: zalando # dbname: owner
17 | preparedDatabases:
18 | bar: {}
19 | postgresql:
20 | version: "13"
21 |
--------------------------------------------------------------------------------
/manifests/minimal-postgres-manifest.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "acid.zalan.do/v1"
2 | kind: postgresql
3 | metadata:
4 | name: acid-minimal-cluster
5 | spec:
6 | teamId: "acid"
7 | volume:
8 | size: 1Gi
9 | numberOfInstances: 2
10 | users:
11 | zalando: # database owner
12 | - superuser
13 | - createdb
14 | foo_user: [] # role for application foo
15 | databases:
16 | foo: zalando # dbname: owner
17 | preparedDatabases:
18 | bar: {}
19 | postgresql:
20 | version: "17"
21 |
--------------------------------------------------------------------------------
/manifests/platform-credentials.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "zalando.org/v1"
2 | kind: PlatformCredentialsSet
3 | metadata:
4 | name: postgresql-operator
5 | spec:
6 | application: postgresql-operator
7 | tokens:
8 | read-only:
9 | privileges:
10 | cluster-registry-rw:
11 | privileges:
12 | cluster-rw:
13 | privileges:
14 |
--------------------------------------------------------------------------------
/manifests/postgres-operator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: postgres-operator
5 | labels:
6 | application: postgres-operator
7 | spec:
8 | replicas: 1
9 | strategy:
10 | type: "Recreate"
11 | selector:
12 | matchLabels:
13 | name: postgres-operator
14 | template:
15 | metadata:
16 | labels:
17 | name: postgres-operator
18 | spec:
19 | serviceAccountName: postgres-operator
20 | containers:
21 | - name: postgres-operator
22 | image: ghcr.io/zalando/postgres-operator:v1.14.0
23 | imagePullPolicy: IfNotPresent
24 | resources:
25 | requests:
26 | cpu: 100m
27 | memory: 250Mi
28 | limits:
29 | cpu: 500m
30 | memory: 500Mi
31 | securityContext:
32 | runAsUser: 1000
33 | runAsNonRoot: true
34 | readOnlyRootFilesystem: true
35 | allowPrivilegeEscalation: false
36 | env:
37 | # provided additional ENV vars can overwrite individual config map entries
38 | - name: CONFIG_MAP_NAME
39 | value: "postgres-operator"
40 | # In order to use the CRD OperatorConfiguration instead, uncomment these lines and comment out the two lines above
41 | # - name: POSTGRES_OPERATOR_CONFIGURATION_OBJECT
42 | # value: postgresql-operator-default-configuration
43 | # Define an ID to isolate controllers from each other
44 | # - name: CONTROLLER_ID
45 | # value: "second-operator"
46 |
--------------------------------------------------------------------------------
/manifests/postgres-pod-priority-class.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: scheduling.k8s.io/v1
2 | description: 'This priority class must be used only for databases controlled by the
3 | Postgres operator'
4 | kind: PriorityClass
5 | metadata:
6 | labels:
7 | application: postgres-operator
8 | name: postgres-pod-priority
9 | preemptionPolicy: PreemptLowerPriority
10 | globalDefault: false
11 | value: 1000000
12 |
--------------------------------------------------------------------------------
/manifests/postgresteam.crd.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apiextensions.k8s.io/v1
2 | kind: CustomResourceDefinition
3 | metadata:
4 | name: postgresteams.acid.zalan.do
5 | spec:
6 | group: acid.zalan.do
7 | names:
8 | kind: PostgresTeam
9 | listKind: PostgresTeamList
10 | plural: postgresteams
11 | singular: postgresteam
12 | shortNames:
13 | - pgteam
14 | categories:
15 | - all
16 | scope: Namespaced
17 | versions:
18 | - name: v1
19 | served: true
20 | storage: true
21 | subresources:
22 | status: {}
23 | schema:
24 | openAPIV3Schema:
25 | type: object
26 | required:
27 | - kind
28 | - apiVersion
29 | - spec
30 | properties:
31 | kind:
32 | type: string
33 | enum:
34 | - PostgresTeam
35 | apiVersion:
36 | type: string
37 | enum:
38 | - acid.zalan.do/v1
39 | spec:
40 | type: object
41 | properties:
42 | additionalSuperuserTeams:
43 | type: object
44 | description: "Map for teamId and associated additional superuser teams"
45 | additionalProperties:
46 | type: array
47 | nullable: true
48 | description: "List of teams to become Postgres superusers"
49 | items:
50 | type: string
51 | additionalTeams:
52 | type: object
53 | description: "Map for teamId and associated additional teams"
54 | additionalProperties:
55 | type: array
56 | nullable: true
57 | description: "List of teams whose members will also be added to the Postgres cluster"
58 | items:
59 | type: string
60 | additionalMembers:
61 | type: object
62 | description: "Map for teamId and associated additional users"
63 | additionalProperties:
64 | type: array
65 | nullable: true
66 | description: "List of users who will also be added to the Postgres cluster"
67 | items:
68 | type: string
69 |
--------------------------------------------------------------------------------
/manifests/standby-manifest.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "acid.zalan.do/v1"
2 | kind: postgresql
3 | metadata:
4 | name: acid-standby-cluster
5 | spec:
6 | teamId: "acid"
7 | volume:
8 | size: 1Gi
9 | numberOfInstances: 1
10 | postgresql:
11 | version: "17"
12 | # Make this a standby cluster and provide either the s3 bucket path of source cluster or the remote primary host for continuous streaming.
13 | standby:
14 | # s3_wal_path: "s3://mybucket/spilo/acid-minimal-cluster/abcd1234-2a4b-4b2a-8c9c-c1234defg567/wal/14/"
15 | standby_host: "acid-minimal-cluster.default"
16 | # standby_port: "5432"
17 |
--------------------------------------------------------------------------------
/manifests/user-facing-clusterroles.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | labels:
5 | rbac.authorization.k8s.io/aggregate-to-admin: "true"
6 | name: zalando-postgres-operator:users:admin
7 | rules:
8 | - apiGroups:
9 | - acid.zalan.do
10 | resources:
11 | - postgresqls
12 | - postgresqls/status
13 | verbs:
14 | - create
15 | - delete
16 | - deletecollection
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 |
23 | ---
24 | apiVersion: rbac.authorization.k8s.io/v1
25 | kind: ClusterRole
26 | metadata:
27 | labels:
28 | rbac.authorization.k8s.io/aggregate-to-edit: "true"
29 | name: zalando-postgres-operator:users:edit
30 | rules:
31 | - apiGroups:
32 | - acid.zalan.do
33 | resources:
34 | - postgresqls
35 | verbs:
36 | - create
37 | - update
38 | - patch
39 | - delete
40 |
41 | ---
42 | apiVersion: rbac.authorization.k8s.io/v1
43 | kind: ClusterRole
44 | metadata:
45 | labels:
46 | rbac.authorization.k8s.io/aggregate-to-view: "true"
47 | name: zalando-postgres-operator:users:view
48 | rules:
49 | - apiGroups:
50 | - acid.zalan.do
51 | resources:
52 | - postgresqls
53 | - postgresqls/status
54 | verbs:
55 | - get
56 | - list
57 | - watch
58 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Postgres Operator
2 | repo_url: https://github.com/zalando/postgres-operator
3 | theme: readthedocs
4 |
5 | nav:
6 | - Concepts: 'index.md'
7 | - Quickstart: 'quickstart.md'
8 | - Postgres Operator UI: 'operator-ui.md'
9 | - Admin guide: 'administrator.md'
10 | - User guide: 'user.md'
11 | - Developer guide: 'developer.md'
12 | - Reference:
13 | - Config parameters: 'reference/operator_parameters.md'
14 | - Manifest parameters: 'reference/cluster_manifest.md'
15 | - CLI options and environment: 'reference/command_line_and_environment.md'
16 |
--------------------------------------------------------------------------------
/mocks/mocks.go:
--------------------------------------------------------------------------------
1 | package mocks
2 |
--------------------------------------------------------------------------------
/pkg/apis/acid.zalan.do/register.go:
--------------------------------------------------------------------------------
1 | package acidzalando
2 |
3 | const (
4 | // GroupName is the group name for the operator CRDs
5 | GroupName = "acid.zalan.do"
6 | )
7 |
--------------------------------------------------------------------------------
/pkg/apis/acid.zalan.do/v1/const.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | // ClusterStatusUnknown etc : status of a Postgres cluster known to the operator
4 | const (
5 | ClusterStatusUnknown = ""
6 | ClusterStatusCreating = "Creating"
7 | ClusterStatusUpdating = "Updating"
8 | ClusterStatusUpdateFailed = "UpdateFailed"
9 | ClusterStatusSyncFailed = "SyncFailed"
10 | ClusterStatusAddFailed = "CreateFailed"
11 | ClusterStatusRunning = "Running"
12 | ClusterStatusInvalid = "Invalid"
13 | )
14 |
15 | const (
16 | serviceNameMaxLength = 63
17 | clusterNameMaxLength = serviceNameMaxLength - len("-repl")
18 | serviceNameRegexString = `^[a-z]([-a-z0-9]*[a-z0-9])?
19 | )
20 |
--------------------------------------------------------------------------------
/pkg/apis/acid.zalan.do/v1/doc.go:
--------------------------------------------------------------------------------
1 | // Package v1 is the v1 version of the API.
2 | // +k8s:deepcopy-gen=package,register
3 |
4 | // +groupName=acid.zalan.do
5 |
6 | package v1
7 |
--------------------------------------------------------------------------------
/pkg/apis/acid.zalan.do/v1/postgres_team_type.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5 | )
6 |
7 | // +genclient
8 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
9 |
10 | // PostgresTeam defines Custom Resource Definition Object for team management.
11 | type PostgresTeam struct {
12 | metav1.TypeMeta `json:",inline"`
13 | metav1.ObjectMeta `json:"metadata,omitempty"`
14 |
15 | Spec PostgresTeamSpec `json:"spec"`
16 | }
17 |
18 | // PostgresTeamSpec defines the specification for the PostgresTeam TPR.
19 | type PostgresTeamSpec struct {
20 | AdditionalSuperuserTeams map[string][]string `json:"additionalSuperuserTeams,omitempty"`
21 | AdditionalTeams map[string][]string `json:"additionalTeams,omitempty"`
22 | AdditionalMembers map[string][]string `json:"additionalMembers,omitempty"`
23 | }
24 |
25 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
26 |
27 | // PostgresTeamList defines a list of PostgresTeam definitions.
28 | type PostgresTeamList struct {
29 | metav1.TypeMeta `json:",inline"`
30 | metav1.ListMeta `json:"metadata"`
31 |
32 | Items []PostgresTeam `json:"items"`
33 | }
34 |
--------------------------------------------------------------------------------
/pkg/apis/acid.zalan.do/v1/register.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | acidzalando "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do"
5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6 | "k8s.io/apimachinery/pkg/runtime"
7 | "k8s.io/apimachinery/pkg/runtime/schema"
8 | )
9 |
10 | // APIVersion of the `postgresql` and `operator` CRDs
11 | const (
12 | APIVersion = "v1"
13 | )
14 |
15 | var (
16 | // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
17 |
18 | // SchemeBuilder : An instance of runtime.SchemeBuilder, global for this package
19 | SchemeBuilder runtime.SchemeBuilder
20 | localSchemeBuilder = &SchemeBuilder
21 | //AddToScheme is localSchemeBuilder.AddToScheme
22 | AddToScheme = localSchemeBuilder.AddToScheme
23 | //SchemeGroupVersion has GroupName and APIVersion
24 | SchemeGroupVersion = schema.GroupVersion{Group: acidzalando.GroupName, Version: APIVersion}
25 | )
26 |
27 | func init() {
28 | // We only register manually written functions here. The registration of the
29 | // generated functions takes place in the generated files. The separation
30 | // makes the code compile even when the generated files are missing.
31 | localSchemeBuilder.Register(addKnownTypes)
32 | }
33 |
34 | // Resource takes an unqualified resource and returns a Group qualified GroupResource
35 | func Resource(resource string) schema.GroupResource {
36 | return SchemeGroupVersion.WithResource(resource).GroupResource()
37 | }
38 |
39 | // Adds the list of known types to api.Scheme.
40 | func addKnownTypes(scheme *runtime.Scheme) error {
41 | // AddKnownType assumes derives the type kind from the type name, which is always uppercase.
42 | // For our CRDs we use lowercase names historically, therefore we have to supply the name separately.
43 | // TODO: User uppercase CRDResourceKind of our types in the next major API version
44 | scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("postgresql"), &Postgresql{})
45 | scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("postgresqlList"), &PostgresqlList{})
46 | scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("PostgresTeam"), &PostgresTeam{})
47 | scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("PostgresTeamList"), &PostgresTeamList{})
48 | scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("OperatorConfiguration"),
49 | &OperatorConfiguration{})
50 | scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("OperatorConfigurationList"),
51 | &OperatorConfigurationList{})
52 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
53 | return nil
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/apis/zalando.org/register.go:
--------------------------------------------------------------------------------
1 | package zalando
2 |
3 | const (
4 | // GroupName is the group name for the operator CRDs
5 | GroupName = "zalando.org"
6 | )
7 |
--------------------------------------------------------------------------------
/pkg/apis/zalando.org/v1/register.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "github.com/zalando/postgres-operator/pkg/apis/zalando.org"
5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6 | "k8s.io/apimachinery/pkg/runtime"
7 | "k8s.io/apimachinery/pkg/runtime/schema"
8 | "k8s.io/client-go/kubernetes/scheme"
9 | )
10 |
11 | // APIVersion of the `fabriceventstream` CRD
12 | const (
13 | APIVersion = "v1"
14 | )
15 |
16 | var (
17 | schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
18 | AddToScheme = schemeBuilder.AddToScheme
19 | )
20 |
21 | func init() {
22 | err := AddToScheme(scheme.Scheme)
23 | if err != nil {
24 | panic(err)
25 | }
26 | }
27 |
28 | // SchemeGroupVersion is the group version used to register these objects.
29 | var SchemeGroupVersion = schema.GroupVersion{Group: zalando.GroupName, Version: APIVersion}
30 |
31 | // Resource takes an unqualified resource and returns a Group-qualified GroupResource.
32 | func Resource(resource string) schema.GroupResource {
33 | return SchemeGroupVersion.WithResource(resource).GroupResource()
34 | }
35 |
36 | // addKnownTypes adds the set of types defined in this package to the supplied scheme.
37 | func addKnownTypes(scheme *runtime.Scheme) error {
38 | scheme.AddKnownTypes(SchemeGroupVersion,
39 | &FabricEventStream{},
40 | &FabricEventStreamList{},
41 | )
42 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
43 | return nil
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/apiserver/apiserver_test.go:
--------------------------------------------------------------------------------
1 | package apiserver
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | const (
8 | clusterStatusTest = "/clusters/test-namespace/testcluster/"
9 | clusterStatusNumericTest = "/clusters/test-namespace-1/testcluster/"
10 | clusterLogsTest = "/clusters/test-namespace/testcluster/logs/"
11 | teamTest = "/clusters/test-id/"
12 | )
13 |
14 | func TestUrlRegexps(t *testing.T) {
15 | if clusterStatusURL.FindStringSubmatch(clusterStatusTest) == nil {
16 | t.Errorf("clusterStatusURL can't match %s", clusterStatusTest)
17 | }
18 |
19 | if clusterStatusURL.FindStringSubmatch(clusterStatusNumericTest) == nil {
20 | t.Errorf("clusterStatusURL can't match %s", clusterStatusNumericTest)
21 | }
22 |
23 | if clusterLogsURL.FindStringSubmatch(clusterLogsTest) == nil {
24 | t.Errorf("clusterLogsURL can't match %s", clusterLogsTest)
25 | }
26 |
27 | if teamURL.FindStringSubmatch(teamTest) == nil {
28 | t.Errorf("teamURL can't match %s", teamTest)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/cluster/connection_pooler_new_test.go:
--------------------------------------------------------------------------------
1 | package cluster
2 |
3 | import (
4 | "testing"
5 |
6 | "context"
7 |
8 | appsv1 "k8s.io/api/apps/v1"
9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 |
11 | "k8s.io/apimachinery/pkg/labels"
12 |
13 | "k8s.io/client-go/kubernetes/fake"
14 | )
15 |
16 | func TestFakeClient(t *testing.T) {
17 | clientSet := fake.NewSimpleClientset()
18 | namespace := "default"
19 |
20 | l := labels.Set(map[string]string{
21 | "application": "spilo",
22 | })
23 |
24 | deployment := &appsv1.Deployment{
25 | ObjectMeta: metav1.ObjectMeta{
26 | Name: "my-deployment1",
27 | Namespace: namespace,
28 | Labels: l,
29 | },
30 | }
31 |
32 | clientSet.AppsV1().Deployments(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{})
33 |
34 | deployment2, _ := clientSet.AppsV1().Deployments(namespace).Get(context.TODO(), "my-deployment1", metav1.GetOptions{})
35 |
36 | if deployment.ObjectMeta.Name != deployment2.ObjectMeta.Name {
37 | t.Errorf("Deployments are not equal")
38 | }
39 |
40 | deployments, _ := clientSet.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: "application=spilo"})
41 |
42 | if len(deployments.Items) != 1 {
43 | t.Errorf("Label search does not work")
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/cluster/exec.go:
--------------------------------------------------------------------------------
1 | package cluster
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "fmt"
7 | "strings"
8 |
9 | v1 "k8s.io/api/core/v1"
10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11 | "k8s.io/client-go/kubernetes/scheme"
12 | "k8s.io/client-go/tools/remotecommand"
13 |
14 | "github.com/zalando/postgres-operator/pkg/spec"
15 | "github.com/zalando/postgres-operator/pkg/util/constants"
16 | )
17 |
18 | // ExecCommand executes arbitrary command inside the pod
19 | func (c *Cluster) ExecCommand(podName *spec.NamespacedName, command ...string) (string, error) {
20 | c.setProcessName("executing command %q", strings.Join(command, " "))
21 |
22 | var (
23 | execOut bytes.Buffer
24 | execErr bytes.Buffer
25 | )
26 |
27 | pod, err := c.KubeClient.Pods(podName.Namespace).Get(context.TODO(), podName.Name, metav1.GetOptions{})
28 | if err != nil {
29 | return "", fmt.Errorf("could not get pod info: %v", err)
30 | }
31 |
32 | // iterate through all containers looking for the one running PostgreSQL.
33 | targetContainer := -1
34 | for i, cr := range pod.Spec.Containers {
35 | if cr.Name == constants.PostgresContainerName {
36 | targetContainer = i
37 | break
38 | }
39 | }
40 |
41 | if targetContainer < 0 {
42 | return "", fmt.Errorf("could not find %s container to exec to", constants.PostgresContainerName)
43 | }
44 |
45 | req := c.KubeClient.RESTClient.Post().
46 | Resource("pods").
47 | Name(podName.Name).
48 | Namespace(podName.Namespace).
49 | SubResource("exec")
50 | req.VersionedParams(&v1.PodExecOptions{
51 | Container: pod.Spec.Containers[targetContainer].Name,
52 | Command: command,
53 | Stdout: true,
54 | Stderr: true,
55 | }, scheme.ParameterCodec)
56 |
57 | exec, err := remotecommand.NewSPDYExecutor(c.RestConfig, "POST", req.URL())
58 | if err != nil {
59 | return "", fmt.Errorf("failed to init executor: %v", err)
60 | }
61 |
62 | err = exec.StreamWithContext(context.TODO(), remotecommand.StreamOptions{
63 | Stdout: &execOut,
64 | Stderr: &execErr,
65 | Tty: false,
66 | })
67 |
68 | if err != nil {
69 | return "", fmt.Errorf("could not execute: %v", err)
70 | }
71 |
72 | if execErr.Len() > 0 {
73 | return "", fmt.Errorf("stderr: %v", execErr.String())
74 | }
75 |
76 | return execOut.String(), nil
77 | }
78 |
--------------------------------------------------------------------------------
/pkg/cluster/filesystems.go:
--------------------------------------------------------------------------------
1 | package cluster
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/zalando/postgres-operator/pkg/spec"
8 | "github.com/zalando/postgres-operator/pkg/util/constants"
9 | "github.com/zalando/postgres-operator/pkg/util/filesystems"
10 | )
11 |
12 | func (c *Cluster) getPostgresFilesystemInfo(podName *spec.NamespacedName) (device, fstype string, err error) {
13 | out, err := c.ExecCommand(podName, "bash", "-c", fmt.Sprintf("df -T %s|tail -1", constants.PostgresDataMount))
14 | if err != nil {
15 | return "", "", err
16 | }
17 | fields := strings.Fields(out)
18 | if len(fields) < 2 {
19 | return "", "", fmt.Errorf("too few fields in the df output")
20 | }
21 |
22 | return fields[0], fields[1], nil
23 | }
24 |
25 | func (c *Cluster) resizePostgresFilesystem(podName *spec.NamespacedName, resizers []filesystems.FilesystemResizer) error {
26 | // resize2fs always writes to stderr, and ExecCommand considers a non-empty stderr an error
27 | // first, determine the device and the filesystem
28 | deviceName, fsType, err := c.getPostgresFilesystemInfo(podName)
29 | if err != nil {
30 | return fmt.Errorf("could not get device and type for the postgres filesystem: %v", err)
31 | }
32 | for _, resizer := range resizers {
33 | if !resizer.CanResizeFilesystem(fsType) {
34 | continue
35 | }
36 | err := resizer.ResizeFilesystem(deviceName, func(cmd string) (out string, err error) {
37 | return c.ExecCommand(podName, "bash", "-c", cmd)
38 | })
39 |
40 | return err
41 | }
42 | return fmt.Errorf("could not resize filesystem: no compatible resizers for the filesystem of type %q", fsType)
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/cluster/types.go:
--------------------------------------------------------------------------------
1 | package cluster
2 |
3 | import (
4 | "time"
5 |
6 | acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
7 | appsv1 "k8s.io/api/apps/v1"
8 | v1 "k8s.io/api/core/v1"
9 | policyv1 "k8s.io/api/policy/v1"
10 | "k8s.io/apimachinery/pkg/types"
11 | )
12 |
13 | // PostgresRole describes role of the node
14 | type PostgresRole string
15 |
16 | const (
17 | // spilo roles
18 | Master PostgresRole = "master"
19 | Replica PostgresRole = "replica"
20 | Patroni PostgresRole = "config"
21 |
22 | // roles returned by Patroni cluster endpoint
23 | Leader PostgresRole = "leader"
24 | StandbyLeader PostgresRole = "standby_leader"
25 | SyncStandby PostgresRole = "sync_standby"
26 | )
27 |
28 | // PodEventType represents the type of a pod-related event
29 | type PodEventType string
30 |
31 | // Possible values for the EventType
32 | const (
33 | PodEventAdd PodEventType = "ADD"
34 | PodEventUpdate PodEventType = "UPDATE"
35 | PodEventDelete PodEventType = "DELETE"
36 | )
37 |
38 | // PodEvent describes the event for a single Pod
39 | type PodEvent struct {
40 | ResourceVersion string
41 | PodName types.NamespacedName
42 | PrevPod *v1.Pod
43 | CurPod *v1.Pod
44 | EventType PodEventType
45 | }
46 |
47 | // Process describes process of the cluster
48 | type Process struct {
49 | Name string
50 | StartTime time.Time
51 | }
52 |
53 | // WorkerStatus describes status of the worker
54 | type WorkerStatus struct {
55 | CurrentCluster types.NamespacedName
56 | CurrentProcess Process
57 | }
58 |
59 | // ClusterStatus describes status of the cluster
60 | type ClusterStatus struct {
61 | Team string
62 | Cluster string
63 | Namespace string
64 | MasterService *v1.Service
65 | ReplicaService *v1.Service
66 | MasterEndpoint *v1.Endpoints
67 | ReplicaEndpoint *v1.Endpoints
68 | StatefulSet *appsv1.StatefulSet
69 | PrimaryPodDisruptionBudget *policyv1.PodDisruptionBudget
70 | CriticalOpPodDisruptionBudget *policyv1.PodDisruptionBudget
71 |
72 | CurrentProcess Process
73 | Worker uint32
74 | Status acidv1.PostgresStatus
75 | Spec acidv1.PostgresSpec
76 | Error error
77 | }
78 |
79 | type TemplateParams map[string]interface{}
80 |
81 | type InstallFunction func(schema string, user string) error
82 |
83 | type SyncReason []string
84 |
85 | // no sync happened, empty value
86 | var NoSync SyncReason = []string{}
87 |
--------------------------------------------------------------------------------
/pkg/controller/node_test.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/zalando/postgres-operator/pkg/spec"
7 | v1 "k8s.io/api/core/v1"
8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | )
10 |
11 | const (
12 | readyLabel = "lifecycle-status"
13 | readyValue = "ready"
14 | )
15 |
16 | func newNodeTestController() *Controller {
17 | var controller = NewController(&spec.ControllerConfig{}, "node-test")
18 | return controller
19 | }
20 |
21 | func makeNode(labels map[string]string, isSchedulable bool) *v1.Node {
22 | return &v1.Node{
23 | ObjectMeta: metav1.ObjectMeta{
24 | Namespace: v1.NamespaceDefault,
25 | Labels: labels,
26 | },
27 | Spec: v1.NodeSpec{
28 | Unschedulable: !isSchedulable,
29 | },
30 | }
31 | }
32 |
33 | var nodeTestController = newNodeTestController()
34 |
35 | func TestNodeIsReady(t *testing.T) {
36 | testName := "TestNodeIsReady"
37 | var testTable = []struct {
38 | in *v1.Node
39 | out bool
40 | readinessLabel map[string]string
41 | }{
42 | {
43 | in: makeNode(map[string]string{"foo": "bar"}, true),
44 | out: true,
45 | readinessLabel: map[string]string{readyLabel: readyValue},
46 | },
47 | {
48 | in: makeNode(map[string]string{"foo": "bar"}, false),
49 | out: false,
50 | readinessLabel: map[string]string{readyLabel: readyValue},
51 | },
52 | {
53 | in: makeNode(map[string]string{readyLabel: readyValue}, false),
54 | out: true,
55 | readinessLabel: map[string]string{readyLabel: readyValue},
56 | },
57 | {
58 | in: makeNode(map[string]string{"foo": "bar", "master": "true"}, false),
59 | out: true,
60 | readinessLabel: map[string]string{readyLabel: readyValue},
61 | },
62 | {
63 | in: makeNode(map[string]string{"foo": "bar", "master": "true"}, false),
64 | out: true,
65 | readinessLabel: map[string]string{readyLabel: readyValue},
66 | },
67 | {
68 | in: makeNode(map[string]string{"foo": "bar"}, true),
69 | out: true,
70 | readinessLabel: map[string]string{},
71 | },
72 | {
73 | in: makeNode(map[string]string{"foo": "bar"}, false),
74 | out: false,
75 | readinessLabel: map[string]string{},
76 | },
77 | {
78 | in: makeNode(map[string]string{readyLabel: readyValue}, false),
79 | out: false,
80 | readinessLabel: map[string]string{},
81 | },
82 | {
83 | in: makeNode(map[string]string{"foo": "bar", "master": "true"}, false),
84 | out: true,
85 | readinessLabel: map[string]string{},
86 | },
87 | }
88 | for _, tt := range testTable {
89 | nodeTestController.opConfig.NodeReadinessLabel = tt.readinessLabel
90 | if isReady := nodeTestController.nodeIsReady(tt.in); isReady != tt.out {
91 | t.Errorf("%s: expected response %t does not match the actual %t for the node %#v",
92 | testName, tt.out, isReady, tt.in)
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/pkg/controller/pod.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "context"
5 |
6 | v1 "k8s.io/api/core/v1"
7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | "k8s.io/apimachinery/pkg/runtime"
9 | "k8s.io/apimachinery/pkg/watch"
10 |
11 | "github.com/zalando/postgres-operator/pkg/cluster"
12 | "github.com/zalando/postgres-operator/pkg/spec"
13 | "github.com/zalando/postgres-operator/pkg/util"
14 | "k8s.io/apimachinery/pkg/types"
15 | )
16 |
17 | func (c *Controller) podListFunc(options metav1.ListOptions) (runtime.Object, error) {
18 | opts := metav1.ListOptions{
19 | Watch: options.Watch,
20 | ResourceVersion: options.ResourceVersion,
21 | TimeoutSeconds: options.TimeoutSeconds,
22 | }
23 |
24 | return c.KubeClient.Pods(c.opConfig.WatchedNamespace).List(context.TODO(), opts)
25 | }
26 |
27 | func (c *Controller) podWatchFunc(options metav1.ListOptions) (watch.Interface, error) {
28 | opts := metav1.ListOptions{
29 | Watch: options.Watch,
30 | ResourceVersion: options.ResourceVersion,
31 | TimeoutSeconds: options.TimeoutSeconds,
32 | }
33 |
34 | return c.KubeClient.Pods(c.opConfig.WatchedNamespace).Watch(context.TODO(), opts)
35 | }
36 |
37 | func (c *Controller) dispatchPodEvent(clusterName spec.NamespacedName, event cluster.PodEvent) {
38 | c.clustersMu.RLock()
39 | cluster, ok := c.clusters[clusterName]
40 | c.clustersMu.RUnlock()
41 | if ok {
42 | cluster.ReceivePodEvent(event)
43 | }
44 | }
45 |
46 | func (c *Controller) podAdd(obj interface{}) {
47 | if pod, ok := obj.(*v1.Pod); ok {
48 | c.preparePodEventForDispatch(pod, nil, cluster.PodEventAdd)
49 | }
50 | }
51 |
52 | func (c *Controller) podUpdate(prev, cur interface{}) {
53 | prevPod, ok := prev.(*v1.Pod)
54 | if !ok {
55 | return
56 | }
57 |
58 | curPod, ok := cur.(*v1.Pod)
59 | if !ok {
60 | return
61 | }
62 |
63 | c.preparePodEventForDispatch(curPod, prevPod, cluster.PodEventUpdate)
64 | }
65 |
66 | func (c *Controller) podDelete(obj interface{}) {
67 |
68 | if pod, ok := obj.(*v1.Pod); ok {
69 | c.preparePodEventForDispatch(pod, nil, cluster.PodEventDelete)
70 | }
71 | }
72 |
73 | func (c *Controller) preparePodEventForDispatch(curPod, prevPod *v1.Pod, event cluster.PodEventType) {
74 | podEvent := cluster.PodEvent{
75 | PodName: types.NamespacedName(util.NameFromMeta(curPod.ObjectMeta)),
76 | CurPod: curPod,
77 | PrevPod: prevPod,
78 | EventType: event,
79 | ResourceVersion: curPod.ResourceVersion,
80 | }
81 |
82 | c.dispatchPodEvent(c.podClusterName(curPod), podEvent)
83 | }
84 |
--------------------------------------------------------------------------------
/pkg/controller/types.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "time"
5 |
6 | "k8s.io/apimachinery/pkg/types"
7 |
8 | acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
9 | )
10 |
11 | // EventType contains type of the events for the TPRs and Pods received from Kubernetes
12 | type EventType string
13 |
14 | // Possible values for the EventType
15 | const (
16 | EventAdd EventType = "ADD"
17 | EventUpdate EventType = "UPDATE"
18 | EventDelete EventType = "DELETE"
19 | EventSync EventType = "SYNC"
20 | EventRepair EventType = "REPAIR"
21 | )
22 |
23 | // ClusterEvent carries the payload of the Cluster TPR events.
24 | type ClusterEvent struct {
25 | EventTime time.Time
26 | UID types.UID
27 | EventType EventType
28 | OldSpec *acidv1.Postgresql
29 | NewSpec *acidv1.Postgresql
30 | WorkerID uint32
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | // This package has the automatically generated clientset.
26 | package versioned
27 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | // This package has the automatically generated fake clientset.
26 | package fake
27 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/fake/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | package fake
26 |
27 | import (
28 | acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
29 | zalandov1 "github.com/zalando/postgres-operator/pkg/apis/zalando.org/v1"
30 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 | runtime "k8s.io/apimachinery/pkg/runtime"
32 | schema "k8s.io/apimachinery/pkg/runtime/schema"
33 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
34 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
35 | )
36 |
37 | var scheme = runtime.NewScheme()
38 | var codecs = serializer.NewCodecFactory(scheme)
39 |
40 | var localSchemeBuilder = runtime.SchemeBuilder{
41 | acidv1.AddToScheme,
42 | zalandov1.AddToScheme,
43 | }
44 |
45 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
46 | // of clientsets, like in:
47 | //
48 | // import (
49 | // "k8s.io/client-go/kubernetes"
50 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
51 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
52 | // )
53 | //
54 | // kclientset, _ := kubernetes.NewForConfig(c)
55 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
56 | //
57 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
58 | // correctly.
59 | var AddToScheme = localSchemeBuilder.AddToScheme
60 |
61 | func init() {
62 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
63 | utilruntime.Must(AddToScheme(scheme))
64 | }
65 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/scheme/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | // This package contains the scheme of the automatically generated clientset.
26 | package scheme
27 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/scheme/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | package scheme
26 |
27 | import (
28 | acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
29 | zalandov1 "github.com/zalando/postgres-operator/pkg/apis/zalando.org/v1"
30 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 | runtime "k8s.io/apimachinery/pkg/runtime"
32 | schema "k8s.io/apimachinery/pkg/runtime/schema"
33 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
34 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
35 | )
36 |
37 | var Scheme = runtime.NewScheme()
38 | var Codecs = serializer.NewCodecFactory(Scheme)
39 | var ParameterCodec = runtime.NewParameterCodec(Scheme)
40 | var localSchemeBuilder = runtime.SchemeBuilder{
41 | acidv1.AddToScheme,
42 | zalandov1.AddToScheme,
43 | }
44 |
45 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
46 | // of clientsets, like in:
47 | //
48 | // import (
49 | // "k8s.io/client-go/kubernetes"
50 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
51 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
52 | // )
53 | //
54 | // kclientset, _ := kubernetes.NewForConfig(c)
55 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
56 | //
57 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
58 | // correctly.
59 | var AddToScheme = localSchemeBuilder.AddToScheme
60 |
61 | func init() {
62 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
63 | utilruntime.Must(AddToScheme(Scheme))
64 | }
65 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | // This package has the automatically generated typed clients.
26 | package v1
27 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | // Package fake has the automatically generated clients.
26 | package fake
27 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1/fake/fake_acid.zalan.do_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | package fake
26 |
27 | import (
28 | v1 "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1"
29 | rest "k8s.io/client-go/rest"
30 | testing "k8s.io/client-go/testing"
31 | )
32 |
33 | type FakeAcidV1 struct {
34 | *testing.Fake
35 | }
36 |
37 | func (c *FakeAcidV1) OperatorConfigurations(namespace string) v1.OperatorConfigurationInterface {
38 | return &FakeOperatorConfigurations{c, namespace}
39 | }
40 |
41 | func (c *FakeAcidV1) PostgresTeams(namespace string) v1.PostgresTeamInterface {
42 | return &FakePostgresTeams{c, namespace}
43 | }
44 |
45 | func (c *FakeAcidV1) Postgresqls(namespace string) v1.PostgresqlInterface {
46 | return &FakePostgresqls{c, namespace}
47 | }
48 |
49 | // RESTClient returns a RESTClient that is used to communicate
50 | // with API server by this client implementation.
51 | func (c *FakeAcidV1) RESTClient() rest.Interface {
52 | var ret *rest.RESTClient
53 | return ret
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1/fake/fake_operatorconfiguration.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | package fake
26 |
27 | import (
28 | "context"
29 |
30 | acidzalandov1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
31 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32 | schema "k8s.io/apimachinery/pkg/runtime/schema"
33 | testing "k8s.io/client-go/testing"
34 | )
35 |
36 | // FakeOperatorConfigurations implements OperatorConfigurationInterface
37 | type FakeOperatorConfigurations struct {
38 | Fake *FakeAcidV1
39 | ns string
40 | }
41 |
42 | var operatorconfigurationsResource = schema.GroupVersionResource{Group: "acid.zalan.do", Version: "v1", Resource: "operatorconfigurations"}
43 |
44 | var operatorconfigurationsKind = schema.GroupVersionKind{Group: "acid.zalan.do", Version: "v1", Kind: "OperatorConfiguration"}
45 |
46 | // Get takes name of the operatorConfiguration, and returns the corresponding operatorConfiguration object, and an error if there is any.
47 | func (c *FakeOperatorConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *acidzalandov1.OperatorConfiguration, err error) {
48 | obj, err := c.Fake.
49 | Invokes(testing.NewGetAction(operatorconfigurationsResource, c.ns, name), &acidzalandov1.OperatorConfiguration{})
50 |
51 | if obj == nil {
52 | return nil, err
53 | }
54 | return obj.(*acidzalandov1.OperatorConfiguration), err
55 | }
56 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1/generated_expansion.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | package v1
26 |
27 | type OperatorConfigurationExpansion interface{}
28 |
29 | type PostgresTeamExpansion interface{}
30 |
31 | type PostgresqlExpansion interface{}
32 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/acid.zalan.do/v1/operatorconfiguration.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | package v1
26 |
27 | import (
28 | "context"
29 |
30 | acidzalandov1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
31 | scheme "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/scheme"
32 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33 | rest "k8s.io/client-go/rest"
34 | )
35 |
36 | // OperatorConfigurationsGetter has a method to return a OperatorConfigurationInterface.
37 | // A group's client should implement this interface.
38 | type OperatorConfigurationsGetter interface {
39 | OperatorConfigurations(namespace string) OperatorConfigurationInterface
40 | }
41 |
42 | // OperatorConfigurationInterface has methods to work with OperatorConfiguration resources.
43 | type OperatorConfigurationInterface interface {
44 | Get(ctx context.Context, name string, opts v1.GetOptions) (*acidzalandov1.OperatorConfiguration, error)
45 | OperatorConfigurationExpansion
46 | }
47 |
48 | // operatorConfigurations implements OperatorConfigurationInterface
49 | type operatorConfigurations struct {
50 | client rest.Interface
51 | ns string
52 | }
53 |
54 | // newOperatorConfigurations returns a OperatorConfigurations
55 | func newOperatorConfigurations(c *AcidV1Client, namespace string) *operatorConfigurations {
56 | return &operatorConfigurations{
57 | client: c.RESTClient(),
58 | ns: namespace,
59 | }
60 | }
61 |
62 | // Get takes name of the operatorConfiguration, and returns the corresponding operatorConfiguration object, and an error if there is any.
63 | func (c *operatorConfigurations) Get(ctx context.Context, name string, options v1.GetOptions) (result *acidzalandov1.OperatorConfiguration, err error) {
64 | result = &acidzalandov1.OperatorConfiguration{}
65 | err = c.client.Get().
66 | Namespace(c.ns).
67 | Resource("operatorconfigurations").
68 | Name(name).
69 | VersionedParams(&options, scheme.ParameterCodec).
70 | Do(ctx).
71 | Into(result)
72 | return
73 | }
74 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/zalando.org/v1/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | // This package has the automatically generated typed clients.
26 | package v1
27 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/zalando.org/v1/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | // Package fake has the automatically generated clients.
26 | package fake
27 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/zalando.org/v1/fake/fake_zalando.org_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | package fake
26 |
27 | import (
28 | v1 "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/typed/zalando.org/v1"
29 | rest "k8s.io/client-go/rest"
30 | testing "k8s.io/client-go/testing"
31 | )
32 |
33 | type FakeZalandoV1 struct {
34 | *testing.Fake
35 | }
36 |
37 | func (c *FakeZalandoV1) FabricEventStreams(namespace string) v1.FabricEventStreamInterface {
38 | return &FakeFabricEventStreams{c, namespace}
39 | }
40 |
41 | // RESTClient returns a RESTClient that is used to communicate
42 | // with API server by this client implementation.
43 | func (c *FakeZalandoV1) RESTClient() rest.Interface {
44 | var ret *rest.RESTClient
45 | return ret
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/zalando.org/v1/generated_expansion.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by client-gen. DO NOT EDIT.
24 |
25 | package v1
26 |
27 | type FabricEventStreamExpansion interface{}
28 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/acid.zalan.do/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by informer-gen. DO NOT EDIT.
24 |
25 | package acid
26 |
27 | import (
28 | v1 "github.com/zalando/postgres-operator/pkg/generated/informers/externalversions/acid.zalan.do/v1"
29 | internalinterfaces "github.com/zalando/postgres-operator/pkg/generated/informers/externalversions/internalinterfaces"
30 | )
31 |
32 | // Interface provides access to each of this group's versions.
33 | type Interface interface {
34 | // V1 provides access to shared informers for resources in V1.
35 | V1() v1.Interface
36 | }
37 |
38 | type group struct {
39 | factory internalinterfaces.SharedInformerFactory
40 | namespace string
41 | tweakListOptions internalinterfaces.TweakListOptionsFunc
42 | }
43 |
44 | // New returns a new Interface.
45 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
46 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
47 | }
48 |
49 | // V1 returns a new v1.Interface.
50 | func (g *group) V1() v1.Interface {
51 | return v1.New(g.factory, g.namespace, g.tweakListOptions)
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/acid.zalan.do/v1/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by informer-gen. DO NOT EDIT.
24 |
25 | package v1
26 |
27 | import (
28 | internalinterfaces "github.com/zalando/postgres-operator/pkg/generated/informers/externalversions/internalinterfaces"
29 | )
30 |
31 | // Interface provides access to all the informers in this group version.
32 | type Interface interface {
33 | // PostgresTeams returns a PostgresTeamInformer.
34 | PostgresTeams() PostgresTeamInformer
35 | // Postgresqls returns a PostgresqlInformer.
36 | Postgresqls() PostgresqlInformer
37 | }
38 |
39 | type version struct {
40 | factory internalinterfaces.SharedInformerFactory
41 | namespace string
42 | tweakListOptions internalinterfaces.TweakListOptionsFunc
43 | }
44 |
45 | // New returns a new Interface.
46 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
47 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
48 | }
49 |
50 | // PostgresTeams returns a PostgresTeamInformer.
51 | func (v *version) PostgresTeams() PostgresTeamInformer {
52 | return &postgresTeamInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
53 | }
54 |
55 | // Postgresqls returns a PostgresqlInformer.
56 | func (v *version) Postgresqls() PostgresqlInformer {
57 | return &postgresqlInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
58 | }
59 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/generic.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by informer-gen. DO NOT EDIT.
24 |
25 | package externalversions
26 |
27 | import (
28 | "fmt"
29 |
30 | v1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
31 | zalandoorgv1 "github.com/zalando/postgres-operator/pkg/apis/zalando.org/v1"
32 | schema "k8s.io/apimachinery/pkg/runtime/schema"
33 | cache "k8s.io/client-go/tools/cache"
34 | )
35 |
36 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other
37 | // sharedInformers based on type
38 | type GenericInformer interface {
39 | Informer() cache.SharedIndexInformer
40 | Lister() cache.GenericLister
41 | }
42 |
43 | type genericInformer struct {
44 | informer cache.SharedIndexInformer
45 | resource schema.GroupResource
46 | }
47 |
48 | // Informer returns the SharedIndexInformer.
49 | func (f *genericInformer) Informer() cache.SharedIndexInformer {
50 | return f.informer
51 | }
52 |
53 | // Lister returns the GenericLister.
54 | func (f *genericInformer) Lister() cache.GenericLister {
55 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
56 | }
57 |
58 | // ForResource gives generic access to a shared informer of the matching type
59 | // TODO extend this to unknown resources with a client pool
60 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
61 | switch resource {
62 | // Group=acid.zalan.do, Version=v1
63 | case v1.SchemeGroupVersion.WithResource("postgresteams"):
64 | return &genericInformer{resource: resource.GroupResource(), informer: f.Acid().V1().PostgresTeams().Informer()}, nil
65 | case v1.SchemeGroupVersion.WithResource("postgresqls"):
66 | return &genericInformer{resource: resource.GroupResource(), informer: f.Acid().V1().Postgresqls().Informer()}, nil
67 |
68 | // Group=zalando.org, Version=v1
69 | case zalandoorgv1.SchemeGroupVersion.WithResource("fabriceventstreams"):
70 | return &genericInformer{resource: resource.GroupResource(), informer: f.Zalando().V1().FabricEventStreams().Informer()}, nil
71 |
72 | }
73 |
74 | return nil, fmt.Errorf("no informer found for %v", resource)
75 | }
76 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by informer-gen. DO NOT EDIT.
24 |
25 | package internalinterfaces
26 |
27 | import (
28 | time "time"
29 |
30 | versioned "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned"
31 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32 | runtime "k8s.io/apimachinery/pkg/runtime"
33 | cache "k8s.io/client-go/tools/cache"
34 | )
35 |
36 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
37 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
38 |
39 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle
40 | type SharedInformerFactory interface {
41 | Start(stopCh <-chan struct{})
42 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
43 | }
44 |
45 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions.
46 | type TweakListOptionsFunc func(*v1.ListOptions)
47 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/zalando.org/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by informer-gen. DO NOT EDIT.
24 |
25 | package zalando
26 |
27 | import (
28 | internalinterfaces "github.com/zalando/postgres-operator/pkg/generated/informers/externalversions/internalinterfaces"
29 | v1 "github.com/zalando/postgres-operator/pkg/generated/informers/externalversions/zalando.org/v1"
30 | )
31 |
32 | // Interface provides access to each of this group's versions.
33 | type Interface interface {
34 | // V1 provides access to shared informers for resources in V1.
35 | V1() v1.Interface
36 | }
37 |
38 | type group struct {
39 | factory internalinterfaces.SharedInformerFactory
40 | namespace string
41 | tweakListOptions internalinterfaces.TweakListOptionsFunc
42 | }
43 |
44 | // New returns a new Interface.
45 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
46 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
47 | }
48 |
49 | // V1 returns a new v1.Interface.
50 | func (g *group) V1() v1.Interface {
51 | return v1.New(g.factory, g.namespace, g.tweakListOptions)
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/zalando.org/v1/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by informer-gen. DO NOT EDIT.
24 |
25 | package v1
26 |
27 | import (
28 | internalinterfaces "github.com/zalando/postgres-operator/pkg/generated/informers/externalversions/internalinterfaces"
29 | )
30 |
31 | // Interface provides access to all the informers in this group version.
32 | type Interface interface {
33 | // FabricEventStreams returns a FabricEventStreamInformer.
34 | FabricEventStreams() FabricEventStreamInformer
35 | }
36 |
37 | type version struct {
38 | factory internalinterfaces.SharedInformerFactory
39 | namespace string
40 | tweakListOptions internalinterfaces.TweakListOptionsFunc
41 | }
42 |
43 | // New returns a new Interface.
44 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
45 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
46 | }
47 |
48 | // FabricEventStreams returns a FabricEventStreamInformer.
49 | func (v *version) FabricEventStreams() FabricEventStreamInformer {
50 | return &fabricEventStreamInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/generated/listers/acid.zalan.do/v1/expansion_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by lister-gen. DO NOT EDIT.
24 |
25 | package v1
26 |
27 | // PostgresTeamListerExpansion allows custom methods to be added to
28 | // PostgresTeamLister.
29 | type PostgresTeamListerExpansion interface{}
30 |
31 | // PostgresTeamNamespaceListerExpansion allows custom methods to be added to
32 | // PostgresTeamNamespaceLister.
33 | type PostgresTeamNamespaceListerExpansion interface{}
34 |
35 | // PostgresqlListerExpansion allows custom methods to be added to
36 | // PostgresqlLister.
37 | type PostgresqlListerExpansion interface{}
38 |
39 | // PostgresqlNamespaceListerExpansion allows custom methods to be added to
40 | // PostgresqlNamespaceLister.
41 | type PostgresqlNamespaceListerExpansion interface{}
42 |
--------------------------------------------------------------------------------
/pkg/generated/listers/zalando.org/v1/expansion_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 Compose, Zalando SE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | SOFTWARE.
21 | */
22 |
23 | // Code generated by lister-gen. DO NOT EDIT.
24 |
25 | package v1
26 |
27 | // FabricEventStreamListerExpansion allows custom methods to be added to
28 | // FabricEventStreamLister.
29 | type FabricEventStreamListerExpansion interface{}
30 |
31 | // FabricEventStreamNamespaceListerExpansion allows custom methods to be added to
32 | // FabricEventStreamNamespaceLister.
33 | type FabricEventStreamNamespaceListerExpansion interface{}
34 |
--------------------------------------------------------------------------------
/pkg/spec/types_test.go:
--------------------------------------------------------------------------------
1 | package spec
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 | )
7 |
8 | const (
9 | mockOperatorNamespace = "acid"
10 | )
11 |
12 | var nnTests = []struct {
13 | s string
14 | expected NamespacedName
15 | expectedMarshal []byte
16 | }{
17 | {`acid/cluster`, NamespacedName{Namespace: mockOperatorNamespace, Name: "cluster"}, []byte(`"acid/cluster"`)},
18 | {`/name`, NamespacedName{Namespace: mockOperatorNamespace, Name: "name"}, []byte(`"acid/name"`)},
19 | {`test`, NamespacedName{Namespace: mockOperatorNamespace, Name: "test"}, []byte(`"acid/test"`)},
20 | }
21 |
22 | var nnErr = []string{"test/", "/", "", "//"}
23 |
24 | func TestNamespacedNameDecode(t *testing.T) {
25 |
26 | for _, tt := range nnTests {
27 | var actual NamespacedName
28 | err := actual.DecodeWorker(tt.s, mockOperatorNamespace)
29 | if err != nil {
30 | t.Errorf("decode error: %v", err)
31 | }
32 | if actual != tt.expected {
33 | t.Errorf("expected: %v, got %#v", tt.expected, actual)
34 | }
35 | }
36 |
37 | }
38 |
39 | func TestNamespacedNameMarshal(t *testing.T) {
40 | for _, tt := range nnTests {
41 | var actual NamespacedName
42 |
43 | m, err := actual.MarshalJSON()
44 | if err != nil {
45 | t.Errorf("marshal error: %v", err)
46 | }
47 | if bytes.Equal(m, tt.expectedMarshal) {
48 | t.Errorf("expected marshal: %v, got %#v", tt.expected, actual)
49 | }
50 | }
51 | }
52 |
53 | func TestNamespacedNameError(t *testing.T) {
54 | for _, tt := range nnErr {
55 | var actual NamespacedName
56 | err := actual.DecodeWorker(tt, mockOperatorNamespace)
57 | if err == nil {
58 | t.Errorf("error expected for %q, got: %#v", tt, actual)
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/pkg/util/config/config_test.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | "testing"
7 | )
8 |
9 | var getMapPairsFromStringTest = []struct {
10 | in string
11 | expected []string
12 | err error
13 | }{
14 | {"log_statement:all, work_mem:'4GB'", []string{"log_statement:all", "work_mem:'4GB'"}, nil},
15 | {`log_statement:none, search_path:'"$user", public'`, []string{"log_statement:none", `search_path:'"$user", public'`}, nil},
16 | {`search_path:'"$user"`, nil, fmt.Errorf("unmatched quote starting at position 13")},
17 | {"", []string{""}, nil},
18 | {",,log_statement:all ,", []string{"", "", "log_statement:all", ""}, nil},
19 | }
20 |
21 | func TestGetMapPairsFromString(t *testing.T) {
22 | for _, tt := range getMapPairsFromStringTest {
23 | got, err := getMapPairsFromString(tt.in)
24 | if err != tt.err && ((err == nil || tt.err == nil) || (err.Error() != tt.err.Error())) {
25 | t.Errorf("TestGetMapPairsFromString with %s: expected error: %#v, got %#v", tt.in, tt.err, err)
26 | }
27 | if !reflect.DeepEqual(got, tt.expected) {
28 | t.Errorf("TestGetMapPairsFromString with %s: expected %#v, got %#v", tt.in, tt.expected, got)
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/util/constants/annotations.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | // Names and values in Kubernetes annotation for services, statefulsets and volumes
4 | const (
5 | ZalandoDNSNameAnnotation = "external-dns.alpha.kubernetes.io/hostname"
6 | ElbTimeoutAnnotationName = "service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout"
7 | ElbTimeoutAnnotationValue = "3600"
8 | KubeIAmAnnotation = "iam.amazonaws.com/role"
9 | VolumeStorateProvisionerAnnotation = "pv.kubernetes.io/provisioned-by"
10 | PostgresqlControllerAnnotationKey = "acid.zalan.do/controller"
11 | )
12 |
--------------------------------------------------------------------------------
/pkg/util/constants/aws.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | import "time"
4 |
5 | // AWS specific constants used by other modules
6 | const (
7 | // EBS related constants
8 | EBSVolumeIDStart = "/vol-"
9 | EBSProvisioner = "kubernetes.io/aws-ebs"
10 | EBSDriver = "ebs.csi.aws.com"
11 | //https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_VolumeModification.html
12 | EBSVolumeStateModifying = "modifying"
13 | EBSVolumeStateOptimizing = "optimizing"
14 | EBSVolumeStateFailed = "failed"
15 | EBSVolumeStateCompleted = "completed"
16 | EBSVolumeResizeWaitInterval = 2 * time.Second
17 | EBSVolumeResizeWaitTimeout = 30 * time.Second
18 | )
19 |
--------------------------------------------------------------------------------
/pkg/util/constants/kubernetes.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | import "time"
4 |
5 | // General kubernetes-related constants
6 | const (
7 | PostgresContainerName = "postgres"
8 | K8sAPIPath = "/apis"
9 |
10 | QueueResyncPeriodPod = 5 * time.Minute
11 | QueueResyncPeriodTPR = 5 * time.Minute
12 | QueueResyncPeriodNode = 5 * time.Minute
13 | )
14 |
--------------------------------------------------------------------------------
/pkg/util/constants/pooler.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | // Connection pooler specific constants
4 | const (
5 | ConnectionPoolerResourceSuffix = "pooler"
6 | ConnectionPoolerUserName = "pooler"
7 | ConnectionPoolerSchemaName = "pooler"
8 | ConnectionPoolerDefaultType = "pgbouncer"
9 | ConnectionPoolerDefaultMode = "transaction"
10 | ConnectionPoolerDefaultCpuRequest = "500m"
11 | ConnectionPoolerDefaultCpuLimit = "1"
12 | ConnectionPoolerDefaultMemoryRequest = "100Mi"
13 | ConnectionPoolerDefaultMemoryLimit = "100Mi"
14 |
15 | ConnectionPoolerContainer = 0
16 | ConnectionPoolerMaxDBConnections = 60
17 | ConnectionPoolerMaxClientConnections = 10000
18 | ConnectionPoolerMinInstances = 1
19 | )
20 |
--------------------------------------------------------------------------------
/pkg/util/constants/postgresql.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | import "time"
4 |
5 | // PostgreSQL specific constants
6 | const (
7 | DataVolumeName = "pgdata"
8 | PostgresDataMount = "/home/postgres/pgdata"
9 | PostgresDataPath = PostgresDataMount + "/pgroot"
10 |
11 | PatroniPGParametersParameterName = "parameters"
12 |
13 | PostgresConnectRetryTimeout = 2 * time.Minute
14 | PostgresConnectTimeout = 15 * time.Second
15 |
16 | ShmVolumeName = "dshm"
17 | ShmVolumePath = "/dev/shm"
18 |
19 | RunVolumeName = "postgresql-run"
20 | RunVolumePath = "/var/run/postgresql"
21 | )
22 |
--------------------------------------------------------------------------------
/pkg/util/constants/roles.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | // Roles specific constants
4 | const (
5 | PasswordLength = 64
6 | SuperuserKeyName = "superuser"
7 | ReplicationUserKeyName = "replication"
8 | ConnectionPoolerUserKeyName = "pooler"
9 | EventStreamUserKeyName = "streamer"
10 | RoleFlagSuperuser = "SUPERUSER"
11 | RoleFlagInherit = "INHERIT"
12 | RoleFlagLogin = "LOGIN"
13 | RoleFlagNoLogin = "NOLOGIN"
14 | RoleFlagCreateRole = "CREATEROLE"
15 | RoleFlagCreateDB = "CREATEDB"
16 | RoleFlagReplication = "REPLICATION"
17 | RoleFlagByPassRLS = "BYPASSRLS"
18 | OwnerRoleNameSuffix = "_owner"
19 | ReaderRoleNameSuffix = "_reader"
20 | WriterRoleNameSuffix = "_writer"
21 | UserRoleNameSuffix = "_user"
22 | DefaultSearchPath = "\"$user\""
23 | RotationUserDateFormat = "060102"
24 | )
25 |
--------------------------------------------------------------------------------
/pkg/util/constants/streams.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | // PostgreSQL specific constants
4 | const (
5 | EventStreamCRDApiVersion = "zalando.org/v1"
6 | EventStreamCRDKind = "FabricEventStream"
7 | EventStreamCRDName = "fabriceventstreams.zalando.org"
8 | EventStreamSourcePGType = "PostgresLogicalReplication"
9 | EventStreamSourceSlotPrefix = "fes"
10 | EventStreamSourcePluginType = "pgoutput"
11 | EventStreamSourceAuthType = "DatabaseAuthenticationSecret"
12 | EventStreamFlowPgGenericType = "PostgresWalToGenericNakadiEvent"
13 | EventStreamSinkNakadiType = "Nakadi"
14 | EventStreamRecoveryDLQType = "DeadLetter"
15 | EventStreamRecoveryIgnoreType = "Ignore"
16 | EventStreamRecoveryNoneType = "None"
17 | EventStreamRecoverySuffix = "dead-letter-queue"
18 | EventStreamCpuAnnotationKey = "fes.zalando.org/FES_CPU"
19 | EventStreamMemoryAnnotationKey = "fes.zalando.org/FES_MEMORY"
20 | )
21 |
--------------------------------------------------------------------------------
/pkg/util/constants/units.go:
--------------------------------------------------------------------------------
1 | package constants
2 |
3 | // Measurement-unit definitions
4 | const (
5 | Gigabyte = 1073741824
6 | )
7 |
--------------------------------------------------------------------------------
/pkg/util/filesystems/ext234.go:
--------------------------------------------------------------------------------
1 | package filesystems
2 |
3 | import (
4 | "fmt"
5 | "regexp"
6 | "strings"
7 | )
8 |
9 | var (
10 | ext2fsSuccessRegexp = regexp.MustCompile(`The filesystem on [/a-z0-9]+ is now \d+ \(\d+\w+\) blocks long.`)
11 | )
12 |
13 | const (
14 | ext2 = "ext2"
15 | ext3 = "ext3"
16 | ext4 = "ext4"
17 | resize2fs = "resize2fs"
18 | )
19 |
20 | //Ext234Resize implements the FilesystemResizer interface for the ext4/3/2fs.
21 | type Ext234Resize struct {
22 | }
23 |
24 | // CanResizeFilesystem checks whether Ext234Resize can resize this filesystem.
25 | func (c *Ext234Resize) CanResizeFilesystem(fstype string) bool {
26 | return fstype == ext2 || fstype == ext3 || fstype == ext4
27 | }
28 |
29 | // ResizeFilesystem calls resize2fs to resize the filesystem if necessary.
30 | func (c *Ext234Resize) ResizeFilesystem(deviceName string, commandExecutor func(cmd string) (out string, err error)) error {
31 | command := fmt.Sprintf("%s %s 2>&1", resize2fs, deviceName)
32 | out, err := commandExecutor(command)
33 | if err != nil {
34 | return err
35 | }
36 | if strings.Contains(out, "Nothing to do") ||
37 | (strings.Contains(out, "on-line resizing required") && ext2fsSuccessRegexp.MatchString(out)) {
38 | return nil
39 | }
40 | return fmt.Errorf("unrecognized output: %q, assuming error", out)
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/util/filesystems/filesystems.go:
--------------------------------------------------------------------------------
1 | package filesystems
2 |
3 | // FilesystemResizer has methods to work with resizing of a filesystem
4 | type FilesystemResizer interface {
5 | CanResizeFilesystem(fstype string) bool
6 | ResizeFilesystem(deviceName string, commandExecutor func(string) (out string, err error)) error
7 | }
8 |
--------------------------------------------------------------------------------
/pkg/util/httpclient/httpclient.go:
--------------------------------------------------------------------------------
1 | package httpclient
2 |
3 | //go:generate mockgen -package mocks -destination=../../../mocks/$GOFILE -source=$GOFILE -build_flags=-mod=vendor
4 |
5 | import "net/http"
6 |
7 | // HTTPClient interface
8 | type HTTPClient interface {
9 | Do(req *http.Request) (*http.Response, error)
10 | Get(url string) (resp *http.Response, err error)
11 | }
12 |
--------------------------------------------------------------------------------
/pkg/util/retryutil/retry_util.go:
--------------------------------------------------------------------------------
1 | package retryutil
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | // RetryTicker is a wrapper aroung time.Tick,
9 | // that allows to mock its implementation
10 | type RetryTicker interface {
11 | Stop()
12 | Tick()
13 | }
14 |
15 | // Ticker is a real implementation of RetryTicker interface
16 | type Ticker struct {
17 | ticker *time.Ticker
18 | }
19 |
20 | // Stop is a convenience wrapper around ticker.Stop
21 | func (t *Ticker) Stop() { t.ticker.Stop() }
22 |
23 | // Tick is a convenience wrapper around ticker.C
24 | func (t *Ticker) Tick() { <-t.ticker.C }
25 |
26 | // Retry is a wrapper around RetryWorker that provides a real RetryTicker
27 | func Retry(interval time.Duration, timeout time.Duration, f func() (bool, error)) error {
28 | //TODO: make the retry exponential
29 | if timeout < interval {
30 | return fmt.Errorf("timeout(%s) should be greater than interval(%v)", timeout, interval)
31 | }
32 | tick := &Ticker{time.NewTicker(interval)}
33 | return RetryWorker(interval, timeout, tick, f)
34 | }
35 |
36 | // RetryWorker calls ConditionFunc until either:
37 | // * it returns boolean true
38 | // * a timeout expires
39 | // * an error occurs
40 | func RetryWorker(
41 | interval time.Duration,
42 | timeout time.Duration,
43 | tick RetryTicker,
44 | f func() (bool, error)) error {
45 |
46 | maxRetries := int(timeout / interval)
47 | defer tick.Stop()
48 |
49 | for i := 0; ; i++ {
50 | ok, err := f()
51 | if err != nil {
52 | return err
53 | }
54 | if ok {
55 | return nil
56 | }
57 | if i+1 == maxRetries {
58 | break
59 | }
60 | tick.Tick()
61 | }
62 | return fmt.Errorf("still failing after %d retries", maxRetries)
63 | }
64 |
--------------------------------------------------------------------------------
/pkg/util/retryutil/retry_util_test.go:
--------------------------------------------------------------------------------
1 | package retryutil
2 |
3 | import (
4 | "errors"
5 | "testing"
6 | )
7 |
8 | type mockTicker struct {
9 | test *testing.T
10 | counter int
11 | }
12 |
13 | func (t *mockTicker) Stop() {}
14 |
15 | func (t *mockTicker) Tick() {
16 | t.counter++
17 | }
18 |
19 | func TestRetryWorkerSuccess(t *testing.T) {
20 | tick := &mockTicker{t, 0}
21 | result := RetryWorker(10, 20, tick, func() (bool, error) {
22 | return true, nil
23 | })
24 |
25 | if result != nil {
26 | t.Errorf("Wrong result, expected: %#v, got: %#v", nil, result)
27 | }
28 |
29 | if tick.counter != 0 {
30 | t.Errorf("Ticker was started once, but it shouldn't be")
31 | }
32 | }
33 |
34 | func TestRetryWorkerOneFalse(t *testing.T) {
35 | var counter = 0
36 |
37 | tick := &mockTicker{t, 0}
38 | result := RetryWorker(1, 3, tick, func() (bool, error) {
39 | counter++
40 | return counter > 1, nil
41 | })
42 |
43 | if result != nil {
44 | t.Errorf("Wrong result, expected: %#v, got: %#v", nil, result)
45 | }
46 |
47 | if tick.counter != 1 {
48 | t.Errorf("Ticker was started %#v, but supposed to be just once", tick.counter)
49 | }
50 | }
51 |
52 | func TestRetryWorkerError(t *testing.T) {
53 | fail := errors.New("Error")
54 |
55 | tick := &mockTicker{t, 0}
56 | result := RetryWorker(1, 3, tick, func() (bool, error) {
57 | return false, fail
58 | })
59 |
60 | if result != fail {
61 | t.Errorf("Wrong result, expected: %#v, got: %#v", fail, result)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/pkg/util/ringlog/ringlog.go:
--------------------------------------------------------------------------------
1 | package ringlog
2 |
3 | import (
4 | "container/list"
5 | "sync"
6 | )
7 |
8 | // RingLogger describes ring logger methods
9 | type RingLogger interface {
10 | Insert(interface{})
11 | Walk() []interface{}
12 | }
13 |
14 | // RingLog is a capped logger with fixed size
15 | type RingLog struct {
16 | sync.RWMutex
17 | size int
18 | list *list.List
19 | }
20 |
21 | // New creates new Ring logger
22 | func New(size int) *RingLog {
23 | r := RingLog{
24 | list: list.New(),
25 | size: size,
26 | }
27 |
28 | return &r
29 | }
30 |
31 | // Insert inserts new entry into the ring logger
32 | func (r *RingLog) Insert(obj interface{}) {
33 | r.Lock()
34 | defer r.Unlock()
35 |
36 | r.list.PushBack(obj)
37 | if r.list.Len() > r.size {
38 | r.list.Remove(r.list.Front())
39 | }
40 | }
41 |
42 | // Walk dumps all the entries from the Ring logger
43 | func (r *RingLog) Walk() []interface{} {
44 | res := make([]interface{}, 0)
45 |
46 | r.RLock()
47 | defer r.RUnlock()
48 |
49 | st := r.list.Front()
50 | for i := 0; i < r.size; i++ {
51 | if st == nil {
52 | return res
53 | }
54 | res = append(res, st.Value)
55 | st = st.Next()
56 | }
57 |
58 | return res
59 | }
60 |
--------------------------------------------------------------------------------
/pkg/util/volumes/volumes.go:
--------------------------------------------------------------------------------
1 | package volumes
2 |
3 | //go:generate mockgen -package mocks -destination=../../../mocks/$GOFILE -source=$GOFILE -build_flags=-mod=vendor
4 |
5 | import v1 "k8s.io/api/core/v1"
6 |
7 | // VolumeProperties ...
8 | type VolumeProperties struct {
9 | VolumeID string
10 | VolumeType string
11 | Size int64
12 | Iops int64
13 | Throughput int64
14 | }
15 |
16 | // VolumeResizer defines the set of methods used to implememnt provider-specific resizing of persistent volumes.
17 | type VolumeResizer interface {
18 | ConnectToProvider() error
19 | IsConnectedToProvider() bool
20 | VolumeBelongsToProvider(pv *v1.PersistentVolume) bool
21 | GetProviderVolumeID(pv *v1.PersistentVolume) (string, error)
22 | ExtractVolumeID(volumeID string) (string, error)
23 | ResizeVolume(providerVolumeID string, newSize int64) error
24 | ModifyVolume(providerVolumeID string, newType *string, newSize *int64, iops *int64, throughput *int64) error
25 | DisconnectFromProvider() error
26 | DescribeVolumes(providerVolumesID []string) ([]VolumeProperties, error)
27 | }
28 |
--------------------------------------------------------------------------------
/pkg/util/volumes/volumes_test.go:
--------------------------------------------------------------------------------
1 | package volumes
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestExtractVolumeID(t *testing.T) {
9 | var tests = []struct {
10 | input string
11 | expectedResult string
12 | expectedErr error
13 | }{
14 | {
15 | input: "aws://eu-central-1c/vol-01234a5b6c78df9gh",
16 | expectedResult: "vol-01234a5b6c78df9gh",
17 | expectedErr: nil,
18 | },
19 | {
20 | input: "vol-0g9fd87c6b5a43210",
21 | expectedResult: "vol-0g9fd87c6b5a43210",
22 | expectedErr: nil,
23 | },
24 | {
25 | input: "aws://eu-central-1c/01234a5b6c78df9g0",
26 | expectedResult: "",
27 | expectedErr: fmt.Errorf("malformed EBS volume id %q", "aws://eu-central-1c/01234a5b6c78df9g0"),
28 | },
29 | {
30 | input: "hg9fd87c6b5a43210",
31 | expectedResult: "",
32 | expectedErr: fmt.Errorf("malformed EBS volume id %q", "hg9fd87c6b5a43210"),
33 | },
34 | }
35 |
36 | resizer := EBSVolumeResizer{}
37 |
38 | for _, tt := range tests {
39 | volumeId, err := resizer.ExtractVolumeID(tt.input)
40 | if volumeId != tt.expectedResult {
41 | t.Errorf("%s expected: %s, got %s", t.Name(), tt.expectedResult, volumeId)
42 | }
43 | if err != tt.expectedErr {
44 | if tt.expectedErr != nil && err.Error() != tt.expectedErr.Error() {
45 | t.Errorf("%s unexpected error: got %v", t.Name(), err)
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ui/.dockerignore:
--------------------------------------------------------------------------------
1 | *#
2 | *.pyc
3 | *~
4 | .*.sw?
5 | .git
6 | __pycache__
7 |
8 | .npm/
9 |
10 | app/node_modules
11 | operator_ui/static/build/*.hot-update.js
12 | operator_ui/static/build/*.hot-update.json
13 |
--------------------------------------------------------------------------------
/ui/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG BASE_IMAGE=registry.opensource.zalan.do/library/python-3.11-slim:latest
2 | ARG NODE_IMAGE=node:lts-alpine
3 |
4 | FROM $NODE_IMAGE AS build
5 |
6 | COPY . /workdir
7 | WORKDIR /workdir/app
8 |
9 | RUN npm install \
10 | && npm run build
11 |
12 | FROM $BASE_IMAGE
13 | LABEL maintainer="Team ACID @ Zalando <team-acid@zalando.de>"
14 |
15 | EXPOSE 8081
16 | WORKDIR /app
17 |
18 | RUN apt-get -qq -y update \
19 | # https://www.psycopg.org/docs/install.html#psycopg-vs-psycopg-binary
20 | && apt-get -qq -y install --no-install-recommends g++ libpq-dev python3-dev python3-distutils \
21 | && apt-get -qq -y clean \
22 | && rm -rf /var/lib/apt/lists/*
23 |
24 | COPY requirements.txt .
25 | COPY start_server.sh .
26 | RUN pip install -r requirements.txt
27 |
28 | COPY operator_ui operator_ui/
29 | COPY --from=build /workdir/operator_ui/static/build/ operator_ui/static/build/
30 |
31 | ARG VERSION=dev
32 | RUN sed -i "s/__version__ = .*/__version__ = '${VERSION}'/" operator_ui/__init__.py
33 |
34 | CMD ["python", "-m", "operator_ui"]
35 |
--------------------------------------------------------------------------------
/ui/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include operator_ui/static *
2 | recursive-include operator_ui/templates *
3 | include *.rst
4 |
--------------------------------------------------------------------------------
/ui/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: clean test appjs docker push mock
2 |
3 | IMAGE ?= registry.opensource.zalan.do/acid/postgres-operator-ui
4 | VERSION ?= $(shell git describe --tags --always --dirty)
5 | TAG ?= $(VERSION)
6 | GITHEAD = $(shell git rev-parse --short HEAD)
7 | GITURL = $(shell git config --get remote.origin.url)
8 | GITSTATUS = $(shell git status --porcelain || echo 'no changes')
9 | TTYFLAGS = $(shell test -t 0 && echo '-it')
10 |
11 | ifdef CDP_PULL_REQUEST_NUMBER
12 | CDP_TAG := -${CDP_BUILD_VERSION}
13 | endif
14 |
15 | default: docker
16 |
17 | clean:
18 | rm -fr operator_ui/static/build
19 |
20 | test:
21 | tox
22 |
23 | appjs:
24 | docker run $(TTYFLAGS) -u $(id -u) -v $(pwd):/workdir -w /workdir/app node:lts-alpine npm install --cache /workdir/.npm
25 | docker run $(TTYFLAGS) -u $(id -u) -v $(pwd):/workdir -w /workdir/app node:lts-alpine npm run build --cache /workdir/.npm
26 |
27 | docker: appjs
28 | echo `(env)`
29 | echo "Tag ${TAG}"
30 | echo "Version ${VERSION}"
31 | echo "CDP tag ${CDP_TAG}"
32 | echo "git describe $(shell git describe --tags --always --dirty)"
33 | docker build --rm -t "$(IMAGE):$(TAG)$(CDP_TAG)" -f Dockerfile .
34 |
35 | push:
36 | docker push "$(IMAGE):$(TAG)$(CDP_TAG)"
37 |
38 | mock:
39 | docker run -it -p 8081:8081 "$(IMAGE):$(TAG)" --mock
40 |
--------------------------------------------------------------------------------
/ui/app/.eslintignore:
--------------------------------------------------------------------------------
1 | src/vendor/*.js
2 |
--------------------------------------------------------------------------------
/ui/app/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | parserOptions:
2 | sourceType: module
3 | env:
4 | browser: true
5 | node: true
6 | es6: true
7 | extends: 'eslint:recommended'
8 | rules:
9 | indent:
10 | - error
11 | - 4
12 | linebreak-style:
13 | - error
14 | - unix
15 | quotes:
16 | - error
17 | - single
18 | prefer-const:
19 | - error
20 | no-redeclare:
21 | - error
22 | no-unused-vars:
23 | - warn
24 | - argsIgnorePattern: "^_"
25 | semi:
26 | - error
27 | - never
28 |
--------------------------------------------------------------------------------
/ui/app/README.rst:
--------------------------------------------------------------------------------
1 | This directory contains the EcmaScript frontend code of the PostgreSQL Operator UI and is only needed during build time.
2 |
3 | The JavaScript application bundle (webpack) will be generated to ``operator_ui/static/build/app*.js`` by running:
4 |
5 | .. code-block:: bash
6 |
7 | $ npm install
8 | $ npm run build
9 |
10 | Frontend development is supported by watching the source code and continuously recompiling the webpack:
11 |
12 | .. code-block:: bash
13 |
14 | $ npm start
15 |
--------------------------------------------------------------------------------
/ui/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postgres-operator-ui",
3 | "version": "1.14.0",
4 | "description": "PostgreSQL Operator UI",
5 | "main": "src/app.js",
6 | "config": {
7 | "buildDir": "../operator_ui/static/build"
8 | },
9 | "scripts": {
10 | "prestart": "npm install",
11 | "start": "NODE_ENV=development webpack --watch",
12 | "webpack": "webpack --config ./webpack.config.js",
13 | "build": "NODE_ENV=development npm run webpack",
14 | "prewebpack": "npm run clean",
15 | "lint": "eslint ./src/**/*.js",
16 | "clean": "rimraf $npm_package_config_buildDir && mkdir $npm_package_config_buildDir"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/zalando/postgres-operator.git"
21 | },
22 | "author": "",
23 | "license": "ISC",
24 | "bugs": {
25 | "url": "https://github.com/zalando/postgres-operator.git/issues"
26 | },
27 | "homepage": "https://github.com/zalando/postgres-operator.git#readme",
28 | "dependencies": {
29 | "@babel/core": "^7.20.12",
30 | "@babel/polyfill": "^7.12.1",
31 | "@babel/runtime": "^7.20.13",
32 | "pixi.js": "^7.1.1"
33 | },
34 | "devDependencies": {
35 | "@babel/plugin-transform-runtime": "^7.19.6",
36 | "@babel/preset-env": "^7.20.2",
37 | "babel-loader": "^8.2.5",
38 | "brfs": "^2.0.2",
39 | "dedent-js": "1.0.1",
40 | "eslint": "^8.32.0",
41 | "js-yaml": "4.1.0",
42 | "pug": "^3.0.2",
43 | "rimraf": "^4.1.2",
44 | "riot": "^3.13.2",
45 | "riot-hot-reload": "1.0.0",
46 | "riot-route": "^3.1.4",
47 | "riot-tag-loader": "2.1.0",
48 | "sort-by": "^1.2.0",
49 | "transform-loader": "^0.2.4",
50 | "webpack": "^4.46.0",
51 | "webpack-cli": "^4.10.0"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/ui/app/src/help-edit.tag.pug:
--------------------------------------------------------------------------------
1 | help-edit
2 |
3 | h2 Help
4 |
5 | .well
6 |
7 | h3(style='margin-top: 0')
8 | | Docs
9 |
10 | a(href="{ opts.config.docs_link }")
11 | | more...
12 |
13 | h3 Editing
14 |
15 | p.
16 | The text box shows you the properties that can currently edit. Verify that the preview shows a valid part of the spec before submitting. After a successful submit the changes may take some time to be applied.
17 |
18 | h3 Volume size
19 |
20 | p.
21 | You need to specify in format "123Gi". You can only increase the volume size. You can only increase volume size once very 6 hours, per AWS limitation.
22 |
23 | virtual(
24 | if='{ opts.config.static_network_whitelist && Object.keys(opts.config.static_network_whitelist).length > 0 }'
25 | )
26 | h3 IP Ranges
27 |
28 | // Raw tags are required here, as otherwise either riotjs removes space it shouldn't, or pugjs adds space it shouldn't. And it has to be all in one line, as it has to be a pre tag (otherwise the riotjs compiler breaks the whitespace).
29 | <pre><virtual each="{ network, network_index in Object.keys(opts.config.static_network_whitelist) }"><virtual if="{ network_index > 0 }"><br></virtual> # { network }<br><virtual each="{ range, range_index in opts.config.static_network_whitelist[network] }"> - { range }<virtual if="index < network.length - 1"><br></virtual></virtual></virtual></pre>
30 |
--------------------------------------------------------------------------------
/ui/app/src/help-general.tag.pug:
--------------------------------------------------------------------------------
1 | help-general
2 |
3 | h2 Help
4 |
5 | .well
6 |
7 | h3(style='margin-top: 0')
8 | | Docs
9 |
10 | a(href="{ opts.config.docs_link }")
11 | | more...
12 |
13 | h3 Basics
14 |
15 | p.
16 | The Postgres Operator will use your definition to create a new
17 | PostgreSQL cluster for you. You can either copy the yaml definition
18 | to a repositiory or hit create cluster (not available in prod).
19 |
--------------------------------------------------------------------------------
/ui/app/src/logs.tag.pug:
--------------------------------------------------------------------------------
1 | logs
2 |
3 | h1.page-header(if='{ cluster_path }')
4 | nav(aria-label="breadcrumb")
5 | ol.breadcrumb
6 |
7 | li.breadcrumb-item
8 | a(href='./#/list')
9 | | PostgreSQL clusters
10 |
11 | li.breadcrumb-item
12 | a(href='./#/status/{ cluster_path }')
13 | | { qname }
14 |
15 | li.breadcrumb-item
16 | a(href='./#/logs/{ cluster_path }')
17 | | Logs
18 |
19 | .sk-spinner-pulse(if='{ logs === undefined }')
20 |
21 | .container-fluid(if='{ logs === null }')
22 | p
23 | | Error loading logs. Please
24 | |
25 | a(onclick="window.location.reload(true)") try again
26 | |
27 | | or
28 | |
29 | a(href="./") start over
30 | | .
31 |
32 | .container-fluid(if='{ logs }')
33 |
34 | table.table.table-hover
35 |
36 | tr(each='{ logs }')
37 |
38 | td(each='{ [levels[Level]] }')
39 | span.label.label-font-size(class='label-{ color_class }')
40 | | { label }
41 |
42 | td(style='white-space: pre')
43 | | { Time }
44 |
45 | td(style='font-family: monospace')
46 | | { Message }
47 |
48 | script.
49 |
50 | this.levels = {
51 | "panic": { label: "Panic" , color_class: "danger" },
52 | "fatal": { label: "Fatal" , color_class: "danger" },
53 | "error": { label: "Error" , color_class: "danger" },
54 | "warning": { label: "Warning", color_class: "warning" },
55 | "info": { label: "Info" , color_class: "primary" },
56 | "debug": { label: "Debug" , color_class: "warning" },
57 | }
58 |
59 | this.logs = undefined
60 |
61 | this.on('mount', () => {
62 | if (
63 | this.namespace !== this.opts.namespace
64 | || this.clustername !== this.opts.clustername
65 | ) {
66 | const namespace = this.namespace = this.opts.namespace
67 | const clustername = this.clustername = this.opts.clustername
68 | const qname = this.qname = namespace + '/' + clustername
69 | const cluster_path = this.cluster_path = (
70 | encodeURI(namespace)
71 | + '/' + encodeURI(clustername)
72 | )
73 | ;(
74 | jQuery
75 | .get(`./operator/clusters/${cluster_path}/logs`)
76 | .done(logs => this.logs = logs.reverse())
77 | .fail(() => this.logs = null)
78 | .always(() => this.update())
79 | )
80 | }
81 | })
82 |
--------------------------------------------------------------------------------
/ui/manifests/ingress.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "networking.k8s.io/v1"
2 | kind: "Ingress"
3 | metadata:
4 | name: "postgres-operator-ui"
5 | namespace: "default"
6 | labels:
7 | application: "postgres-operator-ui"
8 | spec:
9 | # ingressClassName: "ingress-nginx"
10 | rules:
11 | - host: "ui.example.org"
12 | http:
13 | paths:
14 | - path: /
15 | pathType: Prefix
16 | backend:
17 | service:
18 | name: "postgres-operator-ui"
19 | port:
20 | number: 80
21 |
--------------------------------------------------------------------------------
/ui/manifests/kustomization.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: kustomize.config.k8s.io/v1beta1
2 | kind: Kustomization
3 | resources:
4 | - deployment.yaml
5 | - ingress.yaml
6 | - service.yaml
7 | - ui-service-account-rbac.yaml
8 |
--------------------------------------------------------------------------------
/ui/manifests/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: "v1"
2 | kind: "Service"
3 | metadata:
4 | name: "postgres-operator-ui"
5 | namespace: "default"
6 | labels:
7 | application: "postgres-operator-ui"
8 | spec:
9 | type: "ClusterIP"
10 | selector:
11 | name: "postgres-operator-ui"
12 | ports:
13 | - port: 80
14 | protocol: "TCP"
15 | targetPort: 8081
16 |
--------------------------------------------------------------------------------
/ui/manifests/ui-service-account-rbac.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: postgres-operator-ui
5 | namespace: default
6 |
7 | ---
8 | apiVersion: rbac.authorization.k8s.io/v1
9 | kind: ClusterRole
10 | metadata:
11 | name: postgres-operator-ui
12 | rules:
13 | - apiGroups:
14 | - acid.zalan.do
15 | resources:
16 | - postgresqls
17 | verbs:
18 | - create
19 | - delete
20 | - get
21 | - list
22 | - patch
23 | - update
24 | - apiGroups:
25 | - ""
26 | resources:
27 | - pods
28 | verbs:
29 | - get
30 | - list
31 | - watch
32 | - apiGroups:
33 | - ""
34 | resources:
35 | - services
36 | verbs:
37 | - get
38 | - list
39 | - apiGroups:
40 | - apps
41 | resources:
42 | - deployments
43 | - statefulsets
44 | verbs:
45 | - get
46 | - list
47 | - apiGroups:
48 | - ""
49 | resources:
50 | - namespaces
51 | verbs:
52 | - get
53 | - list
54 | ---
55 | apiVersion: rbac.authorization.k8s.io/v1
56 | kind: ClusterRoleBinding
57 | metadata:
58 | name: postgres-operator-ui
59 | roleRef:
60 | apiGroup: rbac.authorization.k8s.io
61 | kind: ClusterRole
62 | name: postgres-operator-ui
63 | subjects:
64 | - kind: ServiceAccount
65 | name: postgres-operator-ui
66 | namespace: default
67 |
--------------------------------------------------------------------------------
/ui/operator_ui/__init__.py:
--------------------------------------------------------------------------------
1 | # This version is replaced during release process.
2 | __version__ = '2017.0.dev1'
3 |
--------------------------------------------------------------------------------
/ui/operator_ui/__main__.py:
--------------------------------------------------------------------------------
1 | from .main import main
2 |
3 | main()
4 |
--------------------------------------------------------------------------------
/ui/operator_ui/adapters/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/ui/operator_ui/adapters/__init__.py
--------------------------------------------------------------------------------
/ui/operator_ui/adapters/logger.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from logging.config import dictConfig
3 |
4 | dictConfig(
5 | {
6 | "version": 1,
7 | "disable_existing_loggers": True,
8 | "formatters": {
9 | "json": {
10 | "class": "pythonjsonlogger.jsonlogger.JsonFormatter",
11 | "format": "%(asctime)s %(levelname)s: %(message)s",
12 | }
13 | },
14 | "handlers": {
15 | "stream_handler": {
16 | "class": "logging.StreamHandler",
17 | "formatter": "json",
18 | "stream": "ext://flask.logging.wsgi_errors_stream",
19 | }
20 | },
21 | "root": {
22 | "level": "DEBUG",
23 | "handlers": ["stream_handler"]
24 | }
25 | }
26 | )
27 |
28 |
29 | class Logger:
30 | def __init__(self):
31 | self.logger = logging.getLogger(__name__)
32 |
33 | def debug(self, msg: str, *args, **kwargs):
34 | self.logger.debug(msg, *args, **kwargs)
35 |
36 | def info(self, msg: str, *args, **kwargs):
37 | self.logger.info(msg, *args, **kwargs)
38 |
39 | def error(self, msg: str, *args, **kwargs):
40 | self.logger.error(msg, *args, **kwargs)
41 |
42 | def exception(self, msg: str, *args, **kwargs):
43 | self.logger.exception(msg, *args, **kwargs)
44 |
45 |
46 | logger = Logger()
47 |
--------------------------------------------------------------------------------
/ui/operator_ui/backoff.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 |
4 | def expo(n: int, base=2, factor=1, max_value=None):
5 | """Exponential decay.
6 |
7 | Adapted from https://github.com/litl/backoff/blob/master/backoff.py (MIT License)
8 |
9 | Args:
10 | base: The mathematical base of the exponentiation operation
11 | factor: Factor to multiply the exponentation by.
12 | max_value: The maximum value to yield. Once the value in the
13 | true exponential sequence exceeds this, the value
14 | of max_value will forever after be yielded.
15 | """
16 | a = factor * base ** n
17 | if max_value is None or a < max_value:
18 | return a
19 | else:
20 | return max_value
21 |
22 |
23 | def random_jitter(value, jitter=1):
24 | """Jitter the value a random number of milliseconds.
25 |
26 | Copied from https://github.com/litl/backoff/blob/master/backoff.py (MIT License)
27 |
28 | This adds up to 1 second of additional time to the original value.
29 | Prior to backoff version 1.2 this was the default jitter behavior.
30 | Args:
31 | value: The unadulterated backoff value.
32 | """
33 | return value + random.uniform(0, jitter)
34 |
35 |
36 | def full_jitter(value):
37 | """Jitter the value across the full range (0 to value).
38 |
39 | Copied from https://github.com/litl/backoff/blob/master/backoff.py (MIT License)
40 |
41 | This corresponds to the "Full Jitter" algorithm specified in the
42 | AWS blog's post on the performance of various jitter algorithms.
43 | (http://www.awsarchitectureblog.com/2015/03/backoff.html)
44 |
45 | Args:
46 | value: The unadulterated backoff value.
47 | """
48 | return random.uniform(0, value)
49 |
--------------------------------------------------------------------------------
/ui/operator_ui/mock.py:
--------------------------------------------------------------------------------
1 | import time
2 | import json
3 | import request
4 |
5 |
6 | class MockCluster:
7 |
8 | def get_pods(self):
9 | return [{"name": "cluster-1-XFF", "role": "master", "ip": "localhost", "port": "8080"},
10 | {"name": "cluster-1-XFE", "role": "replica", "ip": "localhost", "port": "8080"},
11 | {"name": "cluster-1-XFS", "role": "replica", "ip": "localhost", "port": "8080"},
12 | {"name": "cluster-2-SJE", "role": "master", "ip": "localhost", "port": "8080"}]
13 |
--------------------------------------------------------------------------------
/ui/operator_ui/static/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando/postgres-operator/51135b07db0fb81f5fe5e6f2eab1d4d894f64cd4/ui/operator_ui/static/favicon-96x96.png
--------------------------------------------------------------------------------
/ui/operator_ui/static/prism.css:
--------------------------------------------------------------------------------
1 | /* http://prismjs.com/download.html?themes=prism&languages=yaml */
2 | /**
3 | * prism.js default theme for JavaScript, CSS and HTML
4 | * Based on dabblet (http://dabblet.com)
5 | * @author Lea Verou
6 | */
7 |
8 | code[class*="language-"],
9 | pre[class*="language-"] {
10 | color: black;
11 | background: none;
12 | text-shadow: 0 1px white;
13 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
14 | text-align: left;
15 | white-space: pre;
16 | word-spacing: normal;
17 | word-break: normal;
18 | word-wrap: normal;
19 | line-height: 1.5;
20 |
21 | -moz-tab-size: 4;
22 | -o-tab-size: 4;
23 | tab-size: 4;
24 |
25 | -webkit-hyphens: none;
26 | -moz-hyphens: none;
27 | -ms-hyphens: none;
28 | hyphens: none;
29 | }
30 |
31 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
32 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
33 | text-shadow: none;
34 | background: #b3d4fc;
35 | }
36 |
37 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
38 | code[class*="language-"]::selection, code[class*="language-"] ::selection {
39 | text-shadow: none;
40 | background: #b3d4fc;
41 | }
42 |
43 | @media print {
44 | code[class*="language-"],
45 | pre[class*="language-"] {
46 | text-shadow: none;
47 | }
48 | }
49 |
50 | /* Code blocks */
51 | pre[class*="language-"] {
52 | padding: 1em;
53 | margin: .5em 0;
54 | overflow: auto;
55 | }
56 |
57 | :not(pre) > code[class*="language-"],
58 | pre[class*="language-"] {
59 | background: #f5f2f0;
60 | }
61 |
62 | /* Inline code */
63 | :not(pre) > code[class*="language-"] {
64 | padding: .1em;
65 | border-radius: .3em;
66 | white-space: normal;
67 | }
68 |
69 | .token.comment,
70 | .token.prolog,
71 | .token.doctype,
72 | .token.cdata {
73 | color: slategray;
74 | }
75 |
76 | .token.punctuation {
77 | color: #999;
78 | }
79 |
80 | .namespace {
81 | opacity: .7;
82 | }
83 |
84 | .token.property,
85 | .token.tag,
86 | .token.boolean,
87 | .token.number,
88 | .token.constant,
89 | .token.symbol,
90 | .token.deleted {
91 | color: #905;
92 | }
93 |
94 | .token.selector,
95 | .token.attr-name,
96 | .token.string,
97 | .token.char,
98 | .token.builtin,
99 | .token.inserted {
100 | color: #690;
101 | }
102 |
103 | .token.operator,
104 | .token.entity,
105 | .token.url,
106 | .language-css .token.string,
107 | .style .token.string {
108 | color: #a67f59;
109 | background: hsla(0, 0%, 100%, .5);
110 | }
111 |
112 | .token.atrule,
113 | .token.attr-value,
114 | .token.keyword {
115 | color: #07a;
116 | }
117 |
118 | .token.function {
119 | color: #DD4A68;
120 | }
121 |
122 | .token.regex,
123 | .token.important,
124 | .token.variable {
125 | color: #e90;
126 | }
127 |
128 | .token.important,
129 | .token.bold {
130 | font-weight: bold;
131 | }
132 | .token.italic {
133 | font-style: italic;
134 | }
135 |
136 | .token.entity {
137 | cursor: help;
138 | }
139 |
140 |
--------------------------------------------------------------------------------
/ui/operator_ui/static/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 70px;
3 | }
4 |
5 | h1, h2, h3 {
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
9 | .font-robot {
10 | font-family: 'Roboto 300', sans-serif;
11 | }
12 |
13 | input:invalid {
14 | color: red;
15 | font-weight: 600;
16 | }
17 |
18 | ul.ips { list-style-type: none; margin: 0; padding: 0; overflow-x: hidden; }
19 | ul.ips li { margin: 0; padding: 0; }
20 | ul.ips label { margin: 0; padding: 0; }
21 |
22 | .panel-heading.collapsible {
23 | cursor: pointer;
24 | }
25 |
26 | .timeline {
27 | cursor: pointer;
28 | }
29 |
30 | .panel-heading .collapsible:after {
31 | color: grey;
32 | content: "\e113";
33 | float: right;
34 | font-family: 'Glyphicons Halflings';
35 | transition: all 0.5s;
36 | }
37 |
38 | .panel-heading.collapsed .collapsible:after {
39 | transform: rotate(-180deg);
40 | }
41 |
42 | :not(form):invalid,select.owner:disabled {
43 | border: 1px solid red;
44 | box-shadow: 0 0 10px red;
45 | }
46 |
47 | .page-header {
48 | margin-top: 0px;
49 | }
50 |
51 | .page-header h1 {
52 | margin-top: 0px;
53 | }
54 |
55 | label {
56 | font-weight: normal;
57 | margin-top: 0;
58 | }
59 |
60 | .sk-spinner-pulse {
61 | background-color: darkblue;
62 | }
63 |
64 | td {
65 | vertical-align: middle !important;
66 | }
67 |
68 | .tooltip {
69 | position: relative;
70 | display: inline-block;
71 | opacity: 1;
72 | font-size: 14px;
73 | font-weight: bold;
74 | z-index: 0;
75 | }
76 | .tooltip:after {
77 | content: '?';
78 | display: inline-block;
79 | font-family: sans-serif;
80 | font-weight: bold;
81 | text-align: center;
82 | width: 16px;
83 | height: 16px;
84 | font-size: 12px;
85 | line-height: 16px;
86 | border-radius: 12px;
87 | padding: 0px;
88 | color: white;
89 | background: black;
90 | border: 1px solid black;
91 | }
92 | .tooltip .tooltiptext {
93 | visibility: hidden;
94 | width: 250px;
95 | background-color: white;
96 | color: #000;
97 | text-align: justify;
98 | border-radius: 6px;
99 | padding: 10px 10px;
100 | position: absolute;
101 | bottom: 150%;
102 | left: 50%;
103 | margin-left: -120px;
104 | border: 1px solid black;
105 | font-weight: normal;
106 | }
107 | .tooltip .tooltiptext::after {
108 | content: "";
109 | position: absolute;
110 | top: 100%;
111 | left: 50%;
112 | margin-left: -5px;
113 | border-width: 5px;
114 | border-style: solid;
115 | border-color: black transparent transparent transparent;
116 | }
117 | .tooltip:hover .tooltiptext {
118 | visibility: visible;
119 | }
120 |
--------------------------------------------------------------------------------
/ui/operator_ui/update.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import time
3 |
4 | import gevent
5 | import json_delta
6 | import requests.exceptions
7 |
8 | from .backoff import expo, random_jitter
9 | from .utils import get_short_error_message
10 |
11 | logger = logging.getLogger(__name__)
12 |
13 |
--------------------------------------------------------------------------------
/ui/requirements.txt:
--------------------------------------------------------------------------------
1 | backoff==2.2.1
2 | boto3==1.34.110
3 | boto==2.49.0
4 | click==8.1.7
5 | Flask==3.0.3
6 | furl==2.1.3
7 | gevent==24.2.1
8 | jq==1.7.0
9 | json_delta>=2.0.2
10 | kubernetes==11.0.0
11 | python-json-logger==2.0.7
12 | requests==2.32.2
13 | stups-tokens>=1.1.19
14 | werkzeug==3.0.6
15 |
--------------------------------------------------------------------------------
/ui/setup.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from setuptools import find_packages, setup
4 | from setuptools.command.test import test as TestCommand
5 |
6 | from pathlib import Path
7 |
8 |
9 | def read_version(package):
10 | with (Path(package) / '__init__.py').open() as fd:
11 | for line in fd:
12 | if line.startswith('__version__ = '):
13 | return line.split()[-1].strip().strip("'")
14 |
15 |
16 | version = read_version('operator_ui')
17 |
18 |
19 | class PyTest(TestCommand):
20 |
21 | user_options = [('cov-html=', None, 'Generate junit html report')]
22 |
23 | def initialize_options(self):
24 | TestCommand.initialize_options(self)
25 | self.cov = None
26 | self.pytest_args = ['--cov', 'operator_ui', '--cov-report', 'term-missing', '-v']
27 | self.cov_html = False
28 |
29 | def finalize_options(self):
30 | TestCommand.finalize_options(self)
31 | if self.cov_html:
32 | self.pytest_args.extend(['--cov-report', 'html'])
33 | self.pytest_args.extend(['tests'])
34 |
35 | def run_tests(self):
36 | import pytest
37 |
38 | errno = pytest.main(self.pytest_args)
39 | sys.exit(errno)
40 |
41 |
42 | def readme():
43 | return open('README.rst', encoding='utf-8').read()
44 |
45 |
46 | tests_require = [
47 | 'pytest',
48 | 'pytest-cov'
49 | ]
50 |
51 | setup(
52 | name='operator-ui',
53 | packages=find_packages(),
54 | version=version,
55 | description='PostgreSQL Kubernetes Operator UI',
56 | long_description=readme(),
57 | author='team-acid@zalando.de',
58 | url='https://github.com/postgres-operator',
59 | keywords='PostgreSQL Kubernetes Operator UI',
60 | license='MIT',
61 | tests_require=tests_require,
62 | extras_require={'tests': tests_require},
63 | cmdclass={'test': PyTest},
64 | test_suite='tests',
65 | classifiers=[
66 | 'Development Status :: 3',
67 | 'Intended Audience :: Developers',
68 | 'Intended Audience :: System Administrators',
69 | 'License :: OSI Approved :: MIT',
70 | 'Operating System :: OS Independent',
71 | 'Programming Language :: Python',
72 | 'Programming Language :: Python :: 3.11',
73 | 'Topic :: System :: Clustering',
74 | 'Topic :: System :: Monitoring',
75 | ],
76 | include_package_data=True, # needed to include JavaScript (see MANIFEST.in)
77 | entry_points={'console_scripts': ['operator-ui = operator_ui.main:main']}
78 | )
79 |
--------------------------------------------------------------------------------
/ui/start_server.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | /usr/bin/python3 -m operator_ui
3 |
--------------------------------------------------------------------------------
/ui/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist=py35,flake8,eslint
3 |
4 | [tox:travis]
5 | 3.5=py35,flake8,eslint
6 |
7 | [testenv]
8 | deps=pytest
9 | commands=
10 | pip install -r requirements.txt
11 | python setup.py test
12 |
13 | [testenv:flake8]
14 | deps=flake8
15 | commands=python setup.py flake8
16 |
17 | [testenv:eslint]
18 | whitelist_externals=eslint
19 | changedir=app
20 | commands=eslint src
21 |
22 | [flake8]
23 | max-line-length=160
24 | ignore=E402
25 |
26 | [pylama]
27 | ignore=E402
28 |
--------------------------------------------------------------------------------