├── .dockerignore ├── .github ├── dependabot.yml └── workflows │ ├── anchore-analysis.yml │ ├── ci.yaml │ ├── codeql-analysis.yml │ ├── docker.yml │ ├── helm.yml │ └── license.yml ├── .gitignore ├── .grype.yaml ├── .licensei.toml ├── ADOPTERS.md ├── Dockerfile ├── LICENSE ├── Makefile ├── NOTICE ├── PROJECT ├── README.md ├── charts └── thanos-operator │ ├── .helmignore │ ├── Chart.yaml │ ├── crds │ ├── monitoring.banzaicloud.io_objectstores.yaml │ ├── monitoring.banzaicloud.io_receivers.yaml │ ├── monitoring.banzaicloud.io_storeendpoints.yaml │ ├── monitoring.banzaicloud.io_thanos.yaml │ ├── monitoring.banzaicloud.io_thanosendpoints.yaml │ └── monitoring.banzaicloud.io_thanospeers.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── ingress.yaml │ ├── role.yaml │ ├── role_binding.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ └── tests │ │ └── test-connection.yaml │ └── values.yaml ├── cmd └── docs.go ├── config ├── certmanager │ ├── certificate.yaml │ ├── kustomization.yaml │ └── kustomizeconfig.yaml ├── crd │ ├── bases │ │ ├── monitoring.banzaicloud.io_objectstores.yaml │ │ ├── monitoring.banzaicloud.io_receivers.yaml │ │ ├── monitoring.banzaicloud.io_storeendpoints.yaml │ │ ├── monitoring.banzaicloud.io_thanos.yaml │ │ ├── monitoring.banzaicloud.io_thanosendpoints.yaml │ │ └── monitoring.banzaicloud.io_thanospeers.yaml │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ └── patches │ │ ├── cainjection_in_objectstores.yaml │ │ ├── cainjection_in_storeendpoints.yaml │ │ ├── cainjection_in_thanos.yaml │ │ ├── webhook_in_objectstores.yaml │ │ ├── webhook_in_storeendpoints.yaml │ │ └── webhook_in_thanos.yaml ├── default │ ├── kustomization.yaml │ ├── manager_auth_proxy_patch.yaml │ ├── manager_webhook_patch.yaml │ └── webhookcainjection_patch.yaml ├── manager │ ├── kustomization.yaml │ └── manager.yaml ├── prometheus │ ├── kustomization.yaml │ └── monitor.yaml ├── rbac │ ├── auth_proxy_role.yaml │ ├── auth_proxy_role_binding.yaml │ ├── auth_proxy_service.yaml │ ├── kustomization.yaml │ ├── leader_election_role.yaml │ ├── leader_election_role_binding.yaml │ ├── objectstore_editor_role.yaml │ ├── objectstore_viewer_role.yaml │ ├── role.yaml │ ├── role_binding.yaml │ ├── storeendpoint_editor_role.yaml │ ├── storeendpoint_viewer_role.yaml │ ├── thanos_editor_role.yaml │ └── thanos_viewer_role.yaml ├── samples │ ├── bucketweb │ │ └── monitoring_v1apha1_bucketweb.yaml │ ├── endpoint │ │ └── monitoring_v1alpha1_thanos.yaml │ ├── monitoring_v1alpha1_objectstore.yaml │ ├── monitoring_v1alpha1_receiver.yaml │ ├── monitoring_v1alpha1_storeendpoint.yaml │ ├── monitoring_v1alpha1_thanos.yaml │ └── monitoring_v1alpha1_thanos_override.yaml └── webhook │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ ├── manifests.yaml │ └── service.yaml ├── controllers ├── objectstore_controller.go ├── rbac.go ├── receiver_controller.go ├── servicemonitor_watch_controller.go ├── storeendpoint_controller.go ├── suite_test.go ├── thanos_controller.go ├── thanosendpoint_controller.go └── thanospeer_controller.go ├── dashboards ├── bucket-replicate.json ├── compact.json ├── dashboards.md ├── overview.json ├── query.json ├── receive.json ├── rule.json ├── sidecar.json └── store.json ├── docs ├── README.md ├── architecture.md ├── deployment.md ├── developers.md ├── img │ ├── Thanos-multi-cluster.png │ ├── Thanos-observer-cluster.png │ ├── logo │ │ ├── helm.svg │ │ └── thanos_operator_vertical.svg │ └── thanos-single-cluster2.png ├── license.md ├── quickstarts │ ├── README.md │ └── single_cluster_thanos.md ├── setups.md ├── tls.md └── types │ ├── Readme.md │ ├── objectstore_types.md │ ├── receiver_types.md │ ├── storeendpoint_types.md │ ├── thanos_types.md │ ├── thanosendpoint_types.md │ └── thanospeer_types.md ├── go.mod ├── go.sum ├── hack ├── boilerplate.go.txt ├── grpc-ingress-mtls.sh ├── grpc-ingress.sh ├── minio.yaml ├── object-store.yaml ├── query-to-query-tls.sh ├── thanos-remote-write.yaml └── thanos-sidecar.yaml ├── main.go └── pkg ├── resources ├── bucketweb │ ├── bucketweb.go │ ├── deployment.go │ ├── ingress.go │ ├── poddistributionbudget.go │ └── service.go ├── common.go ├── compactor │ ├── compactor.go │ ├── deployment.go │ ├── persistentvolumeclaim.go │ ├── service.go │ └── servicemonitor.go ├── componentreconciler.go ├── objectstore.go ├── query │ ├── deployment.go │ ├── grafanadatasource.go │ ├── ingress.go │ ├── query.go │ ├── service.go │ └── servicemonitor.go ├── query_frontend │ ├── deployment.go │ ├── ingress.go │ ├── query_fronted.go │ └── service.go ├── receiver │ ├── component.go │ ├── hashring.go │ ├── hashring_test.go │ ├── ingress.go │ ├── receiver.go │ ├── service.go │ ├── servicemonitor.go │ └── statefulset.go ├── rule │ ├── ingress.go │ ├── rule.go │ ├── service.go │ ├── servicemonitor.go │ └── statefulset.go ├── sidecar │ ├── ingress.go │ ├── service.go │ └── sidecar.go ├── store │ ├── deployment.go │ ├── ingress.go │ ├── service.go │ ├── servicemonitor.go │ └── store.go ├── storeendpoint.go ├── tagparam.go ├── thanos.go ├── thanosendpoint │ ├── query.go │ ├── reconciler.go │ └── storeendpoint.go ├── thanospeer │ ├── query.go │ └── reconciler.go └── types.go └── sdk ├── api └── v1alpha1 │ ├── groupversion_info.go │ ├── objectstore_types.go │ ├── receiver_types.go │ ├── storeendpoint_types.go │ ├── thanos_types.go │ ├── thanosendpoint_types.go │ ├── thanospeer_types.go │ └── zz_generated.deepcopy.go ├── go.mod ├── go.sum ├── resourcebuilder ├── component.go └── zz_generated.deepcopy.go └── static ├── gen ├── crds │ └── generated.go └── rbac │ └── generated.go └── main.go /.dockerignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | charts/ 3 | docs/ 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "docker" 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/anchore-analysis.yml: -------------------------------------------------------------------------------- 1 | # This workflow checks out code, builds an image, performs a container image 2 | # vulnerability scan with Anchore's Grype tool, and integrates the results with GitHub Advanced Security 3 | # code scanning feature. For more information on the Anchore scan action usage 4 | # and parameters, see https://github.com/anchore/scan-action. For more 5 | # information on Anchore's container image scanning tool Grype, see 6 | # https://github.com/anchore/grype 7 | name: Anchore Container Scan 8 | on: push 9 | jobs: 10 | Anchore-Build-Scan: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout the code 14 | uses: actions/checkout@v2 15 | - name: Build the Docker image 16 | run: docker build . --file Dockerfile --tag banzaicloud/thanos-operator:latest 17 | - name: Run the Anchore scan action itself with GitHub Advanced Security code scanning integration enabled 18 | uses: anchore/scan-action@v3 19 | with: 20 | image: "banzaicloud/thanos-operator:latest" 21 | acs-report-enable: true 22 | - name: Upload Anchore Scan Report 23 | uses: github/codeql-action/upload-sarif@v1 24 | with: 25 | sarif_file: results.sarif 26 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | env: 10 | GOFLAGS: '-mod=readonly' 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Set up Go 18 | uses: actions/setup-go@v2 19 | with: 20 | go-version: 1.17 21 | 22 | - name: Checkout code 23 | uses: actions/checkout@v2 24 | 25 | - name: Run checks 26 | env: 27 | LINTER_FLAGS: '--timeout=2m' 28 | run: make check-circle 29 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | 21 | jobs: 22 | analyze: 23 | name: Analyze 24 | runs-on: ubuntu-latest 25 | 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | language: [ 'go' ] 30 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 31 | # Learn more: 32 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 33 | 34 | steps: 35 | - name: Checkout repository 36 | uses: actions/checkout@v2 37 | 38 | # Initializes the CodeQL tools for scanning. 39 | - name: Initialize CodeQL 40 | uses: github/codeql-action/init@v1 41 | with: 42 | languages: ${{ matrix.language }} 43 | # If you wish to specify custom queries, you can do so here or in a config file. 44 | # By default, queries listed here will override any specified in a config file. 45 | # Prefix the list here with "+" to use these queries and those in the config file. 46 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 47 | 48 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 49 | # If this step fails, then you should remove it and run the build manually (see below) 50 | - name: Autobuild 51 | uses: github/codeql-action/autobuild@v1 52 | 53 | # ℹ️ Command-line programs to run using the OS shell. 54 | # 📚 https://git.io/JvXDl 55 | 56 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 57 | # and modify them (or add more) to build your code if your project 58 | # uses a compiled language 59 | 60 | #- run: | 61 | # make bootstrap 62 | # make release 63 | 64 | - name: Perform CodeQL Analysis 65 | uses: github/codeql-action/analyze@v1 66 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - "[0-9]+.[0-9]+.[0-9]+" 9 | 10 | env: 11 | PLATFORMS: linux/amd64,linux/arm64,linux/arm/v7 12 | 13 | jobs: 14 | docker: 15 | name: Docker 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout code 20 | uses: actions/checkout@v2 21 | 22 | - name: Set up QEMU 23 | uses: docker/setup-qemu-action@v1 24 | - name: Set up Docker Buildx 25 | uses: docker/setup-buildx-action@v1 26 | - name: Cache Docker layers 27 | uses: actions/cache@v2 28 | with: 29 | path: /tmp/.buildx-cache 30 | key: ${{ runner.os }}-buildx-${{ matrix.goarch }}-${{ github.ref }} 31 | restore-keys: | 32 | ${{ runner.os }}-buildx-${{ matrix.goarch }}- 33 | 34 | - name: Login to GitHub Container Registry 35 | uses: docker/login-action@v2 36 | with: 37 | registry: ghcr.io 38 | username: ${{ github.repository_owner }} 39 | password: ${{ secrets.GITHUB_TOKEN }} 40 | 41 | - name: Login to DockerHub 42 | uses: docker/login-action@v2 43 | with: 44 | username: ${{ secrets.DOCKERHUB_USERNAME }} 45 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 46 | 47 | - name: Docker meta for thanos-operator 48 | id: thanos-operator-meta 49 | uses: docker/metadata-action@v4 50 | with: 51 | images: | 52 | ghcr.io/${{ github.repository_owner }}/thanos-operator 53 | banzaicloud/thanos-operator 54 | tags: | 55 | type=raw,value=latest,enable={{is_default_branch}} 56 | 57 | - name: Build thanos-operator 58 | uses: docker/build-push-action@v3 59 | with: 60 | file: Dockerfile 61 | platforms: ${{ env.PLATFORMS }} 62 | push: true 63 | cache-from: type=local,src=/tmp/.buildx-cache 64 | cache-to: type=local,dest=/tmp/.buildx-cache 65 | tags: ${{ steps.thanos-operator-meta.outputs.tags }} 66 | labels: ${{ steps.thanos-operator-meta.outputs.labels }} 67 | -------------------------------------------------------------------------------- /.github/workflows/license.yml: -------------------------------------------------------------------------------- 1 | name: License 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Set up Go 15 | uses: actions/setup-go@v2 16 | with: 17 | go-version: 1.17 18 | 19 | - name: Checkout code 20 | uses: actions/checkout@v2 21 | 22 | - name: Download license information for dependencies 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | run: make license-cache 26 | 27 | - name: Check licenses 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | run: make license-check 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | bin 9 | 10 | # Test binary, build with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | # Kubernetes Generated files - skip generated files, except for vendored files 17 | 18 | !vendor/**/zz_generated.* 19 | 20 | # editor and IDE paraphernalia 21 | .idea 22 | *.swp 23 | *.swo 24 | *~ 25 | 26 | object-store.yaml 27 | thanos-sidecar.yaml 28 | !hack/object-store.yaml 29 | !hack/thanos-sidecar.yaml 30 | 31 | .licensei.cache -------------------------------------------------------------------------------- /.grype.yaml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - vulnerability: CVE-2021-22570 3 | fix-state: unknown 4 | package: 5 | name: google.golang.org/protobuf 6 | version: v1.26.0 7 | type: go-module 8 | - vulnerability: CVE-2015-5237 9 | fix-state: unknown 10 | package: 11 | name: google.golang.org/protobuf 12 | version: v1.26.0 13 | type: go-module 14 | -------------------------------------------------------------------------------- /.licensei.toml: -------------------------------------------------------------------------------- 1 | approved = [ 2 | "mit", 3 | "apache-2.0", 4 | "bsd-3-clause", 5 | "bsd-2-clause", 6 | "mpl-2.0", 7 | ] 8 | 9 | ignored = [ 10 | "github.com/aliyun/aliyun-oss-go-sdk", 11 | "github.com/ghodss/yaml", 12 | "sigs.k8s.io/yaml", # Forked from above 13 | "github.com/gogo/protobuf", 14 | "github.com/golang/protobuf", 15 | "google.golang.org/protobuf", 16 | "github.com/stretchr/testify", 17 | "github.com/fatih/structtag", # BSD-3 18 | "github.com/samuel/go-thrift", # BSD-3 19 | "github.com/uber-go/tally", # MIT 20 | "gopkg.in/fsnotify.v1", # BSD 21 | "github.com/banzaicloud/thanos-operator/pkg/sdk", # Submodule 22 | "emperror.dev/errors", # MIT 23 | 24 | "github.com/davecgh/go-spew", # ISC license 25 | "github.com/oracle/oci-go-sdk", # UPL-1.0 26 | 27 | # Unsupported VCS 28 | "cloud.google.com/go", 29 | "cloud.google.com/go/storage", 30 | "google.golang.org/api", 31 | 32 | "gomodules.xyz/jsonpatch/v2", # ALv2 33 | ] 34 | 35 | [header] 36 | ignorePaths = ["vendor", "client", ".gen", "pkg/sdk/static/gen"] 37 | ignoreFiles = ["mock_*.go", "*_gen.go", "SecretStore_test.go"] 38 | template = """// Copyright :YEAR: Banzai Cloud 39 | // 40 | // Licensed under the Apache License, Version 2.0 (the "License"); 41 | // you may not use this file except in compliance with the License. 42 | // You may obtain a copy of the License at 43 | // 44 | // http://www.apache.org/licenses/LICENSE-2.0 45 | // 46 | // Unless required by applicable law or agreed to in writing, software 47 | // distributed under the License is distributed on an "AS IS" BASIS, 48 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 49 | // See the License for the specific language governing permissions and 50 | // limitations under the License.""" 51 | -------------------------------------------------------------------------------- /ADOPTERS.md: -------------------------------------------------------------------------------- 1 | # Thanos Operator Adopters 2 | 3 | This is a list of production adopters of thanos operator: 4 | 5 | | Company | Industry | 6 | | :--- | :--- | 7 | |[Banzai Cloud](https://banzaicloud.com)|Enterprise Technology| 8 | |[Shipay Tecnologia S.A.](https://shipay.com.br)|Fintech| 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the manager binary 2 | FROM golang:1.17.6 as builder 3 | 4 | WORKDIR /workspace 5 | # Copy the Go Modules manifests 6 | COPY go.mod go.mod 7 | COPY go.sum go.sum 8 | COPY pkg/sdk/go.mod pkg/sdk/go.mod 9 | COPY pkg/sdk/go.sum pkg/sdk/go.sum 10 | 11 | # cache deps before building and copying source so that we don't need to re-download as much 12 | # and so that source changes don't invalidate our downloaded layer 13 | RUN go mod download 14 | 15 | # Copy the go source 16 | COPY main.go main.go 17 | COPY controllers/ controllers/ 18 | COPY pkg/ pkg/ 19 | 20 | # Build 21 | RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -a -o manager main.go 22 | 23 | # Use distroless as minimal base image to package the manager binary 24 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 25 | FROM gcr.io/distroless/static:nonroot 26 | WORKDIR / 27 | COPY --from=builder /workspace/manager . 28 | USER nonroot:nonroot 29 | 30 | ENTRYPOINT ["/manager"] 31 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright © 2018 Banzai Cloud 2 | Copyright © 2021 Cisco Systems, Inc. and/or its affiliates 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | domain: banzaicloud.io 2 | repo: github.com/banzaicloud/thanos-operator 3 | resources: 4 | - group: monitoring 5 | kind: ObjectStore 6 | version: v1alpha1 7 | - group: monitoring 8 | kind: Thanos 9 | version: v1alpha1 10 | - group: monitoring 11 | kind: StoreEndpoint 12 | version: v1alpha1 13 | version: "2" 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | 5 | Docker Automated build 6 | 7 | 8 | 9 | Docker Pulls 10 | 11 | 12 | 13 | CircleCI 14 | 15 | 16 | 17 | Go Report Card 18 | 19 | 20 | 21 | license 22 | 23 | 24 |

25 | 26 | # Thanos Operator 27 | 28 | Thanos Operator is a Kubernetes operator to manage Thanos stack deployment 29 | on Kubernetes. 30 | 31 | ## What is [Thanos](http://thanos.io) 32 | 33 | Open source, highly available Prometheus setup with long term storage capabilities. 34 | 35 | 36 | ## Architecture 37 |

38 | 39 | ## Feature highlights 40 | 41 | - Auto discover endpoints 42 | - Manage persistent volumes 43 | - Metrics configuration 44 | - Simple TLS configuration 45 | 46 | Work in progress 47 | 48 | - Tracing configuration 49 | - Endpoint validation 50 | - Certificate management 51 | - Advanced secret configuration 52 | 53 | ## Documentation 54 | 55 | You can find the complete documentation of thanos operator [here](./docs/README.md) :blue_book:
56 | 57 | ## Commercial support 58 | If you are using the Thanos operator in a production environment and [require commercial support, contact Banzai Cloud](https://banzaicloud.com/contact/), the company backing the development of the Thanos operator. If you are looking for the ultimate observability tool for multi-cluster Kubernetes infrastructures to automate the collection, correlation, and storage of logs and metrics, check out [One Eye](https://banzaicloud.com/products/one-eye/). 59 | 60 | 61 | ## Contributing 62 | 63 | If you find this project useful, help us: 64 | 65 | - Support the development of this project and star this repo! :star: 66 | - If you use the Thanos operator in a production environment, add yourself to the list of production [adopters](https://github.com/banzaicloud/thanos-operator/blob/master/ADOPTERS.md).:metal:
67 | - Help new users with issues they may encounter :muscle: 68 | - Send a pull request with your new features and bug fixes :rocket: 69 | 70 | *For more information, read the [developer documentation](./docs/developers.md)*. 71 | 72 | ## License 73 | 74 | Copyright (c) 2017-2020 [Banzai Cloud, Inc.](https://banzaicloud.com) 75 | 76 | Licensed under the Apache License, Version 2.0 (the "License"); 77 | you may not use this file except in compliance with the License. 78 | You may obtain a copy of the License at 79 | 80 | [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) 81 | 82 | Unless required by applicable law or agreed to in writing, software 83 | distributed under the License is distributed on an "AS IS" BASIS, 84 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 85 | See the License for the specific language governing permissions and 86 | limitations under the License. 87 | -------------------------------------------------------------------------------- /charts/thanos-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 | .vscode/ 23 | -------------------------------------------------------------------------------- /charts/thanos-operator/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: thanos-operator 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | version: 0.3.7 18 | 19 | # This is the version number of the application being deployed. This version number should be 20 | # incremented each time you make changes to the application. 21 | appVersion: 0.3.7 22 | -------------------------------------------------------------------------------- /charts/thanos-operator/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "thanos-operator.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "thanos-operator.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "thanos-operator.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "thanos-operator.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | echo "Visit http://127.0.0.1:8080 to use your application" 20 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /charts/thanos-operator/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "thanos-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 "thanos-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 chart name and version as used by the chart label. 29 | */}} 30 | {{- define "thanos-operator.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | 34 | {{/* 35 | Common labels 36 | */}} 37 | {{- define "thanos-operator.labels" -}} 38 | helm.sh/chart: {{ include "thanos-operator.chart" . }} 39 | {{ include "thanos-operator.selectorLabels" . }} 40 | {{- if .Chart.AppVersion }} 41 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 42 | {{- end }} 43 | app.kubernetes.io/managed-by: {{ .Release.Service }} 44 | {{- end -}} 45 | 46 | {{/* 47 | Selector labels 48 | */}} 49 | {{- define "thanos-operator.selectorLabels" -}} 50 | app.kubernetes.io/name: {{ include "thanos-operator.name" . }} 51 | app.kubernetes.io/instance: {{ .Release.Name }} 52 | {{- end -}} 53 | 54 | {{/* 55 | Create the name of the service account to use 56 | */}} 57 | {{- define "thanos-operator.serviceAccountName" -}} 58 | {{- if .Values.serviceAccount.create -}} 59 | {{ default (include "thanos-operator.fullname" .) .Values.serviceAccount.name }} 60 | {{- else -}} 61 | {{ default "default" .Values.serviceAccount.name }} 62 | {{- end -}} 63 | {{- end -}} 64 | -------------------------------------------------------------------------------- /charts/thanos-operator/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "thanos-operator.fullname" . }} 5 | labels: 6 | {{- include "thanos-operator.labels" . | nindent 4 }} 7 | spec: 8 | replicas: {{ .Values.replicaCount }} 9 | selector: 10 | matchLabels: 11 | {{- include "thanos-operator.selectorLabels" . | nindent 6 }} 12 | template: 13 | metadata: 14 | labels: 15 | {{- include "thanos-operator.selectorLabels" . | nindent 8 }} 16 | spec: 17 | {{- with .Values.imagePullSecrets }} 18 | imagePullSecrets: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | serviceAccountName: {{ include "thanos-operator.serviceAccountName" . }} 22 | securityContext: 23 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 24 | containers: 25 | - name: {{ .Chart.Name }} 26 | securityContext: 27 | {{- toYaml .Values.securityContext | nindent 12 }} 28 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 29 | imagePullPolicy: {{ .Values.image.pullPolicy }} 30 | args: {{ range .Values.extraArgs }} 31 | - {{ . -}} 32 | {{ end }} 33 | ports: 34 | - name: http 35 | containerPort: 8080 36 | protocol: TCP 37 | livenessProbe: 38 | httpGet: 39 | path: /metrics 40 | port: http 41 | readinessProbe: 42 | httpGet: 43 | path: /metrics 44 | port: http 45 | resources: 46 | {{- toYaml .Values.resources | nindent 12 }} 47 | {{- with .Values.nodeSelector }} 48 | nodeSelector: 49 | {{- toYaml . | nindent 8 }} 50 | {{- end }} 51 | {{- with .Values.affinity }} 52 | affinity: 53 | {{- toYaml . | nindent 8 }} 54 | {{- end }} 55 | {{- with .Values.tolerations }} 56 | tolerations: 57 | {{- toYaml . | nindent 8 }} 58 | {{- end }} 59 | -------------------------------------------------------------------------------- /charts/thanos-operator/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "thanos-operator.fullname" . -}} 3 | {{- $svcPort := .Values.service.port -}} 4 | apiVersion: networking.k8s.io/v1 5 | kind: Ingress 6 | metadata: 7 | name: {{ $fullName }} 8 | labels: 9 | {{- include "thanos-operator.labels" . | nindent 4 }} 10 | {{- with .Values.ingress.annotations }} 11 | annotations: 12 | {{- toYaml . | nindent 4 }} 13 | {{- end }} 14 | spec: 15 | {{- if .Values.ingress.tls }} 16 | tls: 17 | {{- range .Values.ingress.tls }} 18 | - hosts: 19 | {{- range .hosts }} 20 | - {{ . | quote }} 21 | {{- end }} 22 | secretName: {{ .secretName }} 23 | {{- end }} 24 | {{- end }} 25 | rules: 26 | {{- range .Values.ingress.hosts }} 27 | - host: {{ .host | quote }} 28 | http: 29 | paths: 30 | {{- range .paths }} 31 | - path: {{ . }} 32 | backend: 33 | service: 34 | name: {{ $fullName }} 35 | port: 36 | number: {{ $svcPort }} 37 | {{- end }} 38 | {{- end }} 39 | {{- end }} 40 | -------------------------------------------------------------------------------- /charts/thanos-operator/templates/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: {{ include "thanos-operator.fullname" . }} 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: {{ include "thanos-operator.fullname" . }} 9 | subjects: 10 | - kind: ServiceAccount 11 | name: {{ include "thanos-operator.serviceAccountName" . }} 12 | namespace: {{ .Release.Namespace}} 13 | -------------------------------------------------------------------------------- /charts/thanos-operator/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "thanos-operator.fullname" . }} 5 | labels: 6 | {{- include "thanos-operator.labels" . | nindent 4 }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.port }} 11 | targetPort: http 12 | protocol: TCP 13 | name: http 14 | selector: 15 | {{- include "thanos-operator.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /charts/thanos-operator/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "thanos-operator.serviceAccountName" . }} 6 | labels: 7 | {{- include "thanos-operator.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end -}} 13 | -------------------------------------------------------------------------------- /charts/thanos-operator/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "thanos-operator.fullname" . }}-test-connection" 5 | labels: 6 | {{- include "thanos-operator.labels" . | nindent 4 }} 7 | annotations: 8 | "helm.sh/hook": test-success 9 | spec: 10 | containers: 11 | - name: wget 12 | image: busybox 13 | command: ['wget'] 14 | args: ['{{ include "thanos-operator.fullname" . }}:{{ .Values.service.port }}'] 15 | restartPolicy: Never 16 | -------------------------------------------------------------------------------- /charts/thanos-operator/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for thanos-operator. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: ghcr.io/banzaicloud/thanos-operator 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart version. 11 | tag: "" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: 25 | 26 | podSecurityContext: {} 27 | # fsGroup: 2000 28 | 29 | securityContext: {} 30 | # capabilities: 31 | # drop: 32 | # - ALL 33 | # readOnlyRootFilesystem: true 34 | # runAsNonRoot: true 35 | # runAsUser: 1000 36 | 37 | service: 38 | type: ClusterIP 39 | port: 80 40 | 41 | ingress: 42 | enabled: false 43 | annotations: {} 44 | # kubernetes.io/ingress.class: nginx 45 | # kubernetes.io/tls-acme: "true" 46 | hosts: 47 | - host: chart-example.local 48 | paths: [] 49 | tls: [] 50 | # - secretName: chart-example-tls 51 | # hosts: 52 | # - chart-example.local 53 | 54 | extraArgs: 55 | - -enable-leader-election=true 56 | 57 | resources: {} 58 | # We usually recommend not to specify default resources and to leave this as a conscious 59 | # choice for the user. This also increases chances charts run on environments with little 60 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 61 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 62 | # limits: 63 | # cpu: 200m 64 | # memory: 256Mi 65 | # requests: 66 | # cpu: 100m 67 | # memory: 128Mi 68 | 69 | nodeSelector: {} 70 | 71 | tolerations: [] 72 | 73 | affinity: {} 74 | -------------------------------------------------------------------------------- /cmd/docs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package main 16 | 17 | import ( 18 | "fmt" 19 | "path/filepath" 20 | 21 | "emperror.dev/errors" 22 | "github.com/MakeNowJust/heredoc" 23 | "github.com/banzaicloud/operator-tools/pkg/docgen" 24 | "github.com/banzaicloud/operator-tools/pkg/utils" 25 | ) 26 | 27 | var logger = utils.Log 28 | 29 | func main() { 30 | crds() 31 | } 32 | 33 | func crds() { 34 | lister := docgen.NewSourceLister( 35 | map[string]docgen.SourceDir{ 36 | "thanos": {Path: "pkg/sdk/api/v1alpha1", DestPath: "docs/types"}, 37 | }, 38 | logger.WithName("lister")) 39 | 40 | lister.IncludeSources = []string{ 41 | ".*types", 42 | } 43 | lister.IgnoredSources = []string{ 44 | ".*", 45 | } 46 | 47 | lister.Index = docgen.NewDoc(docgen.DocItem{ 48 | Name: "Readme", 49 | DestPath: "docs/types", 50 | }, logger.WithName("typedoc")) 51 | 52 | lister.Header = heredoc.Doc(` 53 | # Available Types 54 | 55 | For more information please click on the name 56 |
57 | 58 | | Name | Description | 59 | |---|---|`, 60 | ) 61 | 62 | lister.Footer = heredoc.Doc(` 63 |
64 | `) 65 | 66 | lister.DocGeneratedHook = func(document *docgen.Doc) error { 67 | relPath, err := filepath.Rel(lister.Index.Item.DestPath, document.Item.DestPath) 68 | if err != nil { 69 | return errors.WrapIff(err, "failed to determine relpath for %s", document.Item.DestPath) 70 | } 71 | lister.Index.Append(fmt.Sprintf("| **[%s](%s)** | %s |", 72 | document.DisplayName, 73 | filepath.Join(relPath, document.Item.Name+".md"), 74 | document.Desc)) 75 | return nil 76 | } 77 | 78 | if err := lister.Generate(); err != nil { 79 | panic(err) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /config/certmanager/certificate.yaml: -------------------------------------------------------------------------------- 1 | # The following manifests contain a self-signed issuer CR and a certificate CR. 2 | # More document can be found at https://docs.cert-manager.io 3 | # WARNING: Targets CertManager 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for breaking changes 4 | apiVersion: cert-manager.io/v1alpha2 5 | kind: Issuer 6 | metadata: 7 | name: selfsigned-issuer 8 | namespace: system 9 | spec: 10 | selfSigned: {} 11 | --- 12 | apiVersion: cert-manager.io/v1alpha2 13 | kind: Certificate 14 | metadata: 15 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml 16 | namespace: system 17 | spec: 18 | # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize 19 | dnsNames: 20 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc 21 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local 22 | issuerRef: 23 | kind: Issuer 24 | name: selfsigned-issuer 25 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize 26 | -------------------------------------------------------------------------------- /config/certmanager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - certificate.yaml 3 | 4 | configurations: 5 | - kustomizeconfig.yaml 6 | -------------------------------------------------------------------------------- /config/certmanager/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This configuration is for teaching kustomize how to update name ref and var substitution 2 | nameReference: 3 | - kind: Issuer 4 | group: cert-manager.io 5 | fieldSpecs: 6 | - kind: Certificate 7 | group: cert-manager.io 8 | path: spec/issuerRef/name 9 | 10 | varReference: 11 | - kind: Certificate 12 | group: cert-manager.io 13 | path: spec/commonName 14 | - kind: Certificate 15 | group: cert-manager.io 16 | path: spec/dnsNames 17 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/monitoring.banzaicloud.io_objectstores.yaml 6 | - bases/monitoring.banzaicloud.io_thanos.yaml 7 | - bases/monitoring.banzaicloud.io_receivers.yaml 8 | - bases/monitoring.banzaicloud.io_storeendpoints.yaml 9 | - bases/monitoring.banzaicloud.io_thanosendpoints.yaml 10 | - bases/monitoring.banzaicloud.io_thanospeers.yaml 11 | # +kubebuilder:scaffold:crdkustomizeresource 12 | 13 | patchesStrategicMerge: 14 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 15 | # patches here are for enabling the conversion webhook for each CRD 16 | #- patches/webhook_in_objectstores.yaml 17 | #- patches/webhook_in_thanos.yaml 18 | #- patches/webhook_in_storeendpoints.yaml 19 | # +kubebuilder:scaffold:crdkustomizewebhookpatch 20 | 21 | # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. 22 | # patches here are for enabling the CA injection for each CRD 23 | #- patches/cainjection_in_objectstores.yaml 24 | #- patches/cainjection_in_thanos.yaml 25 | #- patches/cainjection_in_storeendpoints.yaml 26 | # +kubebuilder:scaffold:crdkustomizecainjectionpatch 27 | 28 | # the following config is for teaching kustomize how to do kustomization for CRDs. 29 | configurations: 30 | - kustomizeconfig.yaml 31 | -------------------------------------------------------------------------------- /config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | group: apiextensions.k8s.io 8 | path: spec/conversion/webhookClientConfig/service/name 9 | 10 | namespace: 11 | - kind: CustomResourceDefinition 12 | group: apiextensions.k8s.io 13 | path: spec/conversion/webhookClientConfig/service/namespace 14 | create: false 15 | 16 | varReference: 17 | - path: metadata/annotations 18 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_objectstores.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 8 | name: objectstores.monitoring.banzaicloud.io 9 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_storeendpoints.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 8 | name: storeendpoints.monitoring.banzaicloud.io 9 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_thanos.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 8 | name: thanos.monitoring.banzaicloud.io 9 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_objectstores.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables conversion webhook for CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | name: objectstores.monitoring.banzaicloud.io 7 | spec: 8 | conversion: 9 | strategy: Webhook 10 | webhookClientConfig: 11 | # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, 12 | # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) 13 | caBundle: Cg== 14 | service: 15 | namespace: system 16 | name: webhook-service 17 | path: /convert 18 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_storeendpoints.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables conversion webhook for CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | name: storeendpoints.monitoring.banzaicloud.io 7 | spec: 8 | conversion: 9 | strategy: Webhook 10 | webhookClientConfig: 11 | # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, 12 | # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) 13 | caBundle: Cg== 14 | service: 15 | namespace: system 16 | name: webhook-service 17 | path: /convert 18 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_thanos.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables conversion webhook for CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | name: thanos.monitoring.banzaicloud.io 7 | spec: 8 | conversion: 9 | strategy: Webhook 10 | webhookClientConfig: 11 | # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, 12 | # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) 13 | caBundle: Cg== 14 | service: 15 | namespace: system 16 | name: webhook-service 17 | path: /convert 18 | -------------------------------------------------------------------------------- /config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Adds namespace to all resources. 2 | namespace: default 3 | 4 | # Value of this field is prepended to the 5 | # names of all resources, e.g. a deployment named 6 | # "wordpress" becomes "alices-wordpress". 7 | # Note that it should also match with the prefix (text before '-') of the namespace 8 | # field above. 9 | namePrefix: thanos-operator- 10 | 11 | # Labels to add to all resources and selectors. 12 | #commonLabels: 13 | # someName: someValue 14 | 15 | bases: 16 | - ../crd 17 | - ../rbac 18 | - ../manager 19 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml 20 | #- ../webhook 21 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. 22 | #- ../certmanager 23 | # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. 24 | #- ../prometheus 25 | 26 | patchesStrategicMerge: 27 | # Protect the /metrics endpoint by putting it behind auth. 28 | # Only one of manager_auth_proxy_patch.yaml and 29 | # manager_prometheus_metrics_patch.yaml should be enabled. 30 | - manager_auth_proxy_patch.yaml 31 | # If you want your controller-manager to expose the /metrics 32 | # endpoint w/o any authn/z, uncomment the following line and 33 | # comment manager_auth_proxy_patch.yaml. 34 | # Only one of manager_auth_proxy_patch.yaml and 35 | # manager_prometheus_metrics_patch.yaml should be enabled. 36 | #- manager_prometheus_metrics_patch.yaml 37 | 38 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml 39 | #- manager_webhook_patch.yaml 40 | 41 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 42 | # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. 43 | # 'CERTMANAGER' needs to be enabled to use ca injection 44 | #- webhookcainjection_patch.yaml 45 | 46 | # the following config is for teaching kustomize how to do var substitution 47 | vars: 48 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. 49 | #- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR 50 | # objref: 51 | # kind: Certificate 52 | # group: cert-manager.io 53 | # version: v1alpha2 54 | # name: serving-cert # this name should match the one in certificate.yaml 55 | # fieldref: 56 | # fieldpath: metadata.namespace 57 | #- name: CERTIFICATE_NAME 58 | # objref: 59 | # kind: Certificate 60 | # group: cert-manager.io 61 | # version: v1alpha2 62 | # name: serving-cert # this name should match the one in certificate.yaml 63 | #- name: SERVICE_NAMESPACE # namespace of the service 64 | # objref: 65 | # kind: Service 66 | # version: v1 67 | # name: webhook-service 68 | # fieldref: 69 | # fieldpath: metadata.namespace 70 | #- name: SERVICE_NAME 71 | # objref: 72 | # kind: Service 73 | # version: v1 74 | # name: webhook-service 75 | -------------------------------------------------------------------------------- /config/default/manager_auth_proxy_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch inject a sidecar container which is a HTTP proxy for the controller manager, 2 | # it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: controller-manager 7 | namespace: system 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: kube-rbac-proxy 13 | image: gcr.io/kubebuilder/kube-rbac-proxy:v0.4.1 14 | args: 15 | - "--secure-listen-address=0.0.0.0:8443" 16 | - "--upstream=http://127.0.0.1:8080/" 17 | - "--logtostderr=true" 18 | - "--v=10" 19 | ports: 20 | - containerPort: 8443 21 | name: https 22 | - name: manager 23 | args: 24 | - "--metrics-addr=127.0.0.1:8080" 25 | - "--enable-leader-election" 26 | -------------------------------------------------------------------------------- /config/default/manager_webhook_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | ports: 12 | - containerPort: 9443 13 | name: webhook-server 14 | protocol: TCP 15 | volumeMounts: 16 | - mountPath: /tmp/k8s-webhook-server/serving-certs 17 | name: cert 18 | readOnly: true 19 | volumes: 20 | - name: cert 21 | secret: 22 | defaultMode: 420 23 | secretName: webhook-server-cert 24 | -------------------------------------------------------------------------------- /config/default/webhookcainjection_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch add annotation to admission webhook config and 2 | # the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. 3 | apiVersion: admissionregistration.k8s.io/v1 4 | kind: MutatingWebhookConfiguration 5 | metadata: 6 | name: mutating-webhook-configuration 7 | annotations: 8 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 9 | --- 10 | apiVersion: admissionregistration.k8s.io/v1 11 | kind: ValidatingWebhookConfiguration 12 | metadata: 13 | name: validating-webhook-configuration 14 | annotations: 15 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 16 | -------------------------------------------------------------------------------- /config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | images: 6 | - name: controller 7 | newName: banzaicloud/thanos-operator 8 | newTag: latest 9 | -------------------------------------------------------------------------------- /config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: system 7 | --- 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | name: controller-manager 12 | namespace: system 13 | labels: 14 | control-plane: controller-manager 15 | spec: 16 | selector: 17 | matchLabels: 18 | control-plane: controller-manager 19 | replicas: 1 20 | template: 21 | metadata: 22 | labels: 23 | control-plane: controller-manager 24 | spec: 25 | containers: 26 | - command: 27 | - /manager 28 | args: 29 | - --enable-leader-election 30 | image: controller:latest 31 | name: manager 32 | resources: 33 | limits: 34 | cpu: 100m 35 | memory: 30Mi 36 | requests: 37 | cpu: 100m 38 | memory: 20Mi 39 | terminationGracePeriodSeconds: 10 40 | -------------------------------------------------------------------------------- /config/prometheus/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - monitor.yaml 3 | -------------------------------------------------------------------------------- /config/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Prometheus Monitor Service (Metrics) 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | labels: 7 | control-plane: controller-manager 8 | name: controller-manager-metrics-monitor 9 | namespace: system 10 | spec: 11 | endpoints: 12 | - path: /metrics 13 | port: https 14 | selector: 15 | control-plane: controller-manager 16 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: proxy-role 5 | rules: 6 | - apiGroups: ["authentication.k8s.io"] 7 | resources: 8 | - tokenreviews 9 | verbs: ["create"] 10 | - apiGroups: ["authorization.k8s.io"] 11 | resources: 12 | - subjectaccessreviews 13 | verbs: ["create"] 14 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: proxy-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: proxy-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: controller-manager-metrics-service 7 | namespace: system 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | control-plane: controller-manager 15 | -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - role.yaml 3 | - role_binding.yaml 4 | - leader_election_role.yaml 5 | - leader_election_role_binding.yaml 6 | # Comment the following 3 lines if you want to disable 7 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 8 | # which protects your /metrics endpoint. 9 | - auth_proxy_service.yaml 10 | - auth_proxy_role.yaml 11 | - auth_proxy_role_binding.yaml 12 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - create 16 | - update 17 | - patch 18 | - delete 19 | - apiGroups: 20 | - "" 21 | resources: 22 | - configmaps/status 23 | verbs: 24 | - get 25 | - update 26 | - patch 27 | - apiGroups: 28 | - "" 29 | resources: 30 | - events 31 | verbs: 32 | - create 33 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: leader-election-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: leader-election-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/objectstore_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do edit objectstores. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: objectstore-editor-role 6 | rules: 7 | - apiGroups: 8 | - monitoring.banzaicloud.io 9 | resources: 10 | - objectstores 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - monitoring.banzaicloud.io 21 | resources: 22 | - objectstores/status 23 | verbs: 24 | - get 25 | - patch 26 | - update 27 | -------------------------------------------------------------------------------- /config/rbac/objectstore_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do viewer objectstores. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: objectstore-viewer-role 6 | rules: 7 | - apiGroups: 8 | - monitoring.banzaicloud.io 9 | resources: 10 | - objectstores 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - monitoring.banzaicloud.io 17 | resources: 18 | - objectstores/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/storeendpoint_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do edit storeendpoints. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: storeendpoint-editor-role 6 | rules: 7 | - apiGroups: 8 | - monitoring.banzaicloud.io 9 | resources: 10 | - storeendpoints 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - monitoring.banzaicloud.io 21 | resources: 22 | - storeendpoints/status 23 | verbs: 24 | - get 25 | - patch 26 | - update 27 | -------------------------------------------------------------------------------- /config/rbac/storeendpoint_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do viewer storeendpoints. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: storeendpoint-viewer-role 6 | rules: 7 | - apiGroups: 8 | - monitoring.banzaicloud.io 9 | resources: 10 | - storeendpoints 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - monitoring.banzaicloud.io 17 | resources: 18 | - storeendpoints/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /config/rbac/thanos_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do edit thanos. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: thanos-editor-role 6 | rules: 7 | - apiGroups: 8 | - monitoring.banzaicloud.io 9 | resources: 10 | - thanos 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - monitoring.banzaicloud.io 21 | resources: 22 | - thanos/status 23 | verbs: 24 | - get 25 | - patch 26 | - update 27 | -------------------------------------------------------------------------------- /config/rbac/thanos_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do viewer thanos. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: thanos-viewer-role 6 | rules: 7 | - apiGroups: 8 | - monitoring.banzaicloud.io 9 | resources: 10 | - thanos 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - monitoring.banzaicloud.io 17 | resources: 18 | - thanos/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /config/samples/bucketweb/monitoring_v1apha1_bucketweb.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.banzaicloud.io/v1alpha1 2 | kind: ObjectStore 3 | metadata: 4 | name: bucketweb-sample 5 | spec: 6 | config: 7 | mountFrom: 8 | secretKeyRef: 9 | name: thanos 10 | key: object-store.yaml 11 | bucketWeb: 12 | HTTPIngress: {} 13 | -------------------------------------------------------------------------------- /config/samples/endpoint/monitoring_v1alpha1_thanos.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.banzaicloud.io/v1alpha1 2 | kind: ThanosEndpoint 3 | metadata: 4 | name: thanosendpoint-sample 5 | spec: 6 | queryOverrides: 7 | GRPCIngress: 8 | ingressOverrides: 9 | metadata: 10 | annotations: 11 | kubernetes.io/ingress.class: "nginx" -------------------------------------------------------------------------------- /config/samples/monitoring_v1alpha1_objectstore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.banzaicloud.io/v1alpha1 2 | kind: ObjectStore 3 | metadata: 4 | name: objectstore-sample 5 | spec: 6 | config: 7 | mountFrom: 8 | secretKeyRef: 9 | name: thanos 10 | key: object-store.yaml 11 | bucketWeb: {} 12 | compactor: 13 | dataVolume: 14 | pvc: 15 | spec: 16 | accessModes: 17 | - ReadWriteOnce 18 | resources: 19 | requests: 20 | storage: 1Gi 21 | -------------------------------------------------------------------------------- /config/samples/monitoring_v1alpha1_receiver.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.banzaicloud.io/v1alpha1 2 | kind: Receiver 3 | metadata: 4 | name: receiver-sample 5 | spec: 6 | receiverGroups: 7 | - name: tenant-a 8 | replicas: 2 9 | tenants: ["tenant-a"] 10 | config: 11 | mountFrom: 12 | secretKeyRef: 13 | name: thanos 14 | key: object-store.yaml 15 | dataVolume: 16 | pvc: 17 | spec: 18 | accessModes: 19 | - ReadWriteOnce 20 | resources: 21 | requests: 22 | storage: 1Gi 23 | metrics: 24 | serviceMonitor: true 25 | - name: soft-tenant 26 | config: 27 | mountFrom: 28 | secretKeyRef: 29 | name: thanos 30 | key: object-store.yaml 31 | dataVolume: 32 | pvc: 33 | spec: 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 1Gi 39 | metrics: 40 | serviceMonitor: true 41 | httpIngress: {} 42 | --- 43 | apiVersion: monitoring.banzaicloud.io/v1alpha1 44 | kind: Thanos 45 | metadata: 46 | name: receiver-sample-query 47 | spec: 48 | query: 49 | metrics: 50 | serviceMonitor: true 51 | stores: 52 | - "dnssrv+_grpc._tcp.receiver-sample-receiver-soft-tenant" 53 | - "dnssrv+_grpc._tcp.receiver-sample-receiver-tenant-a" 54 | queryReplicaLabel: 55 | - replica 56 | - receive_replica 57 | grafanaDatasource: true -------------------------------------------------------------------------------- /config/samples/monitoring_v1alpha1_storeendpoint.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.banzaicloud.io/v1alpha1 2 | kind: StoreEndpoint 3 | metadata: 4 | name: storeendpoint-sample 5 | spec: 6 | # Add fields here 7 | thanos: thanos-sample 8 | config: 9 | mountFrom: 10 | secretKeyRef: 11 | name: thanos 12 | key: object-store.yaml 13 | selector: {} 14 | 15 | --- 16 | 17 | #apiVersion: monitoring.banzaicloud.io/v1alpha1 18 | #kind: StoreEndpoint 19 | #metadata: 20 | # name: storeendpoint-sample2 21 | #spec: 22 | # # Add fields here 23 | # thanos: thanos-sample 24 | # config: 25 | # mountFrom: 26 | # secretKeyRef: 27 | # name: thanos 28 | # key: object-store.yaml 29 | # #selector: {} -------------------------------------------------------------------------------- /config/samples/monitoring_v1alpha1_thanos.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.banzaicloud.io/v1alpha1 2 | kind: Thanos 3 | metadata: 4 | name: thanos-sample 5 | spec: 6 | enableRecreateWorkloadOnImmutableFieldChange: true 7 | query: 8 | metrics: 9 | serviceMonitor: true 10 | HTTPIngress: {} 11 | # GRPCIngress: {} 12 | # GRPCClientCertificate: example-com-tls 13 | rule: 14 | metrics: 15 | serviceMonitor: true 16 | dataVolume: 17 | pvc: 18 | spec: 19 | accessModes: 20 | - ReadWriteOnce 21 | resources: 22 | requests: 23 | storage: 1Gi 24 | volumeMode: "Filesystem" 25 | storeGateway: 26 | # GRPCServerCertificate: example-com-tls 27 | metrics: 28 | serviceMonitor: true 29 | -------------------------------------------------------------------------------- /config/samples/monitoring_v1alpha1_thanos_override.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.banzaicloud.io/v1alpha1 2 | kind: Thanos 3 | metadata: 4 | name: thanos-sample 5 | spec: 6 | query: 7 | deploymentOverrides: 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: store 13 | image: quay.io/thanos/thanos:v0.22.0 14 | volumeMounts: 15 | - mountPath: /data 16 | name: pv-storage 17 | volumes: 18 | - name: pv-storage 19 | persistentVolumeClaim: 20 | claimName: storegateway-pvc 21 | -------------------------------------------------------------------------------- /config/webhook/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manifests.yaml 3 | - service.yaml 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /config/webhook/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # the following config is for teaching kustomize where to look at when substituting vars. 2 | # It requires kustomize v2.1.0 or newer to work properly. 3 | nameReference: 4 | - kind: Service 5 | version: v1 6 | fieldSpecs: 7 | - kind: MutatingWebhookConfiguration 8 | group: admissionregistration.k8s.io 9 | path: webhooks/clientConfig/service/name 10 | - kind: ValidatingWebhookConfiguration 11 | group: admissionregistration.k8s.io 12 | path: webhooks/clientConfig/service/name 13 | 14 | namespace: 15 | - kind: MutatingWebhookConfiguration 16 | group: admissionregistration.k8s.io 17 | path: webhooks/clientConfig/service/namespace 18 | create: true 19 | - kind: ValidatingWebhookConfiguration 20 | group: admissionregistration.k8s.io 21 | path: webhooks/clientConfig/service/namespace 22 | create: true 23 | 24 | varReference: 25 | - path: metadata/annotations 26 | -------------------------------------------------------------------------------- /config/webhook/manifests.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banzaicloud/thanos-operator/3aa76e5f291768a15a3dcc13099b7c2ad40031ae/config/webhook/manifests.yaml -------------------------------------------------------------------------------- /config/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: webhook-service 6 | namespace: system 7 | spec: 8 | ports: 9 | - port: 443 10 | targetPort: 9443 11 | selector: 12 | control-plane: controller-manager 13 | -------------------------------------------------------------------------------- /controllers/objectstore_controller.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package controllers 16 | 17 | import ( 18 | "context" 19 | 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | "github.com/banzaicloud/thanos-operator/pkg/resources/bucketweb" 23 | "github.com/banzaicloud/thanos-operator/pkg/resources/compactor" 24 | "github.com/go-logr/logr" 25 | appsv1 "k8s.io/api/apps/v1" 26 | corev1 "k8s.io/api/core/v1" 27 | netv1 "k8s.io/api/networking/v1" 28 | apierrors "k8s.io/apimachinery/pkg/api/errors" 29 | ctrl "sigs.k8s.io/controller-runtime" 30 | "sigs.k8s.io/controller-runtime/pkg/client" 31 | "sigs.k8s.io/controller-runtime/pkg/controller" 32 | 33 | monitoringv1alpha1 "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 34 | ) 35 | 36 | // ObjectStoreReconciler reconciles a ObjectStore object 37 | type ObjectStoreReconciler struct { 38 | Client client.Client 39 | Log logr.Logger 40 | } 41 | 42 | // +kubebuilder:rbac:groups=monitoring.banzaicloud.io,resources=objectstores,verbs=get;list;watch;create;update;patch;delete 43 | // +kubebuilder:rbac:groups=monitoring.banzaicloud.io,resources=objectstores/status,verbs=get;update;patch 44 | 45 | func (r *ObjectStoreReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 46 | result := ctrl.Result{} 47 | log := r.Log.WithValues("objectstore", req.NamespacedName) 48 | 49 | store := &monitoringv1alpha1.ObjectStore{} 50 | err := r.Client.Get(ctx, req.NamespacedName, store) 51 | if err != nil { 52 | if apierrors.IsNotFound(err) { 53 | return result, nil 54 | } 55 | return result, err 56 | } 57 | objectStoreReconciler := resources.NewObjectStoreReconciler(store, reconciler.NewGenericReconciler(r.Client, log, reconciler.ReconcilerOpts{})) 58 | 59 | reconcilers := make([]resources.ComponentReconciler, 0) 60 | 61 | // Bucket Web 62 | reconcilers = append(reconcilers, bucketweb.New(objectStoreReconciler).Reconcile) 63 | // Compactor 64 | reconcilers = append(reconcilers, compactor.New(objectStoreReconciler).Reconcile) 65 | 66 | return resources.RunReconcilers(reconcilers) 67 | } 68 | 69 | func (r *ObjectStoreReconciler) SetupWithManager(mgr ctrl.Manager) (controller.Controller, error) { 70 | return ctrl.NewControllerManagedBy(mgr). 71 | For(&monitoringv1alpha1.ObjectStore{}). 72 | Owns(&appsv1.Deployment{}). 73 | Owns(&corev1.Service{}). 74 | Owns(&netv1.Ingress{}). 75 | Owns(&corev1.PersistentVolumeClaim{}). 76 | Build(r) 77 | } 78 | -------------------------------------------------------------------------------- /controllers/rbac.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package controllers 16 | 17 | // +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;patch;delete 18 | // +kubebuilder:rbac:groups=extensions;apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete 19 | // +kubebuilder:rbac:groups=extensions;networking.k8s.io,resources=ingresses,verbs=get;list;watch;create;update;patch;delete 20 | // +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;create;update;patch;delete 21 | // +kubebuilder:rbac:groups="",resources=services;persistentvolumeclaims;events,verbs=get;list;watch;create;update;patch;delete 22 | // +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors,verbs=get;list;watch;create;update;patch;delete 23 | -------------------------------------------------------------------------------- /controllers/receiver_controller.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package controllers 16 | 17 | import ( 18 | "context" 19 | 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | monitoringv1alpha1 "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 22 | "github.com/go-logr/logr" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | ctrl "sigs.k8s.io/controller-runtime" 25 | "sigs.k8s.io/controller-runtime/pkg/client" 26 | "sigs.k8s.io/controller-runtime/pkg/controller" 27 | 28 | "github.com/banzaicloud/thanos-operator/pkg/resources/receiver" 29 | ) 30 | 31 | func NewReceiverReconciler(client client.Client, logger logr.Logger) *ReceiverReconciler { 32 | return &ReceiverReconciler{ 33 | NativeReconciler: reconciler.NewNativeReconciler( 34 | monitoringv1alpha1.ReceiverName, 35 | reconciler.NewGenericReconciler(client, logger, reconciler.ReconcilerOpts{}), 36 | client, 37 | receiver.NewComponent(client.Scheme()), 38 | func(o runtime.Object) (parent reconciler.ResourceOwner, config interface{}) { 39 | receiver := o.(*monitoringv1alpha1.Receiver) 40 | return receiver, nil 41 | }, 42 | reconciler.NativeReconcilerWithScheme(client.Scheme()), 43 | ), 44 | } 45 | } 46 | 47 | // ReceiverReconciler reconciles a Receiver object 48 | type ReceiverReconciler struct { 49 | *reconciler.NativeReconciler 50 | } 51 | 52 | // +kubebuilder:rbac:groups=monitoring.banzaicloud.io,resources=receivers,verbs=get;list;watch;create;update;patch;delete 53 | // +kubebuilder:rbac:groups=monitoring.banzaicloud.io,resources=receivers/status,verbs=get;update;patch 54 | 55 | func (r *ReceiverReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 56 | result := ctrl.Result{} 57 | 58 | receiver := &monitoringv1alpha1.Receiver{} 59 | if err := r.Client.Get(ctx, req.NamespacedName, receiver); err != nil { 60 | return result, client.IgnoreNotFound(err) 61 | } 62 | 63 | res, err := r.NativeReconciler.Reconcile(receiver) 64 | if res != nil { 65 | result = *res 66 | } 67 | return result, err 68 | } 69 | 70 | func (r *ReceiverReconciler) SetupWithManager(mgr ctrl.Manager) (controller.Controller, error) { 71 | b := ctrl.NewControllerManagedBy(mgr) 72 | r.NativeReconciler.RegisterWatches(b) 73 | return b.Build(r) 74 | } 75 | -------------------------------------------------------------------------------- /controllers/servicemonitor_watch_controller.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package controllers 16 | 17 | import ( 18 | "context" 19 | 20 | "emperror.dev/errors" 21 | "github.com/go-logr/logr" 22 | prometheus "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" 23 | v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 24 | apierrors "k8s.io/apimachinery/pkg/api/errors" 25 | "k8s.io/apimachinery/pkg/runtime" 26 | ctrl "sigs.k8s.io/controller-runtime" 27 | "sigs.k8s.io/controller-runtime/pkg/client" 28 | "sigs.k8s.io/controller-runtime/pkg/controller" 29 | "sigs.k8s.io/controller-runtime/pkg/handler" 30 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 31 | "sigs.k8s.io/controller-runtime/pkg/source" 32 | ) 33 | 34 | type ControllerWithSource struct { 35 | Controller controller.Controller 36 | Source runtime.Object 37 | } 38 | 39 | type ServiceMonitorWatchReconciler struct { 40 | Log logr.Logger 41 | Controllers map[string]ControllerWithSource 42 | Client client.Client 43 | added bool 44 | } 45 | 46 | // +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch 47 | 48 | func (r *ServiceMonitorWatchReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 49 | crd := &v1.CustomResourceDefinition{} 50 | err := r.Client.Get(ctx, req.NamespacedName, crd) 51 | if err != nil { 52 | // Object not found, return. Created objects are automatically garbage collected. 53 | // For additional cleanup logic use finalizers. 54 | if apierrors.IsNotFound(err) { 55 | return reconcile.Result{}, nil 56 | } 57 | return reconcile.Result{}, err 58 | } 59 | 60 | var combinedErr error 61 | if crd.Spec.Names.Kind == "ServiceMonitor" && !r.added { 62 | r.Log.Info("adding watch for ServiceMonitor to all the interested controllers") 63 | for cName, c := range r.Controllers { 64 | err := c.Controller.Watch(&source.Kind{Type: &prometheus.ServiceMonitor{}}, &handler.EnqueueRequestForOwner{ 65 | OwnerType: c.Source, 66 | IsController: true, 67 | }) 68 | if err != nil { 69 | r.Log.Error(err, "unable to add ServiceMonitor watch to controller", "controller", cName) 70 | combinedErr = errors.Combine(combinedErr, err) 71 | } 72 | } 73 | if combinedErr == nil { 74 | r.added = true 75 | } 76 | } 77 | 78 | return ctrl.Result{}, combinedErr 79 | } 80 | 81 | func (r *ServiceMonitorWatchReconciler) SetupWithManager(mgr ctrl.Manager) error { 82 | return ctrl.NewControllerManagedBy(mgr).For(&v1.CustomResourceDefinition{}).Complete(r) 83 | } 84 | -------------------------------------------------------------------------------- /controllers/storeendpoint_controller.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package controllers 16 | 17 | import ( 18 | "context" 19 | 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | "github.com/banzaicloud/thanos-operator/pkg/resources/sidecar" 23 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 24 | "github.com/go-logr/logr" 25 | corev1 "k8s.io/api/core/v1" 26 | netv1 "k8s.io/api/networking/v1" 27 | apierrors "k8s.io/apimachinery/pkg/api/errors" 28 | ctrl "sigs.k8s.io/controller-runtime" 29 | "sigs.k8s.io/controller-runtime/pkg/client" 30 | ) 31 | 32 | // StoreEndpointReconciler reconciles a StoreEndpoint object 33 | type StoreEndpointReconciler struct { 34 | Client client.Client 35 | Log logr.Logger 36 | } 37 | 38 | // +kubebuilder:rbac:groups=monitoring.banzaicloud.io,resources=storeendpoints,verbs=get;list;watch;create;update;patch;delete 39 | // +kubebuilder:rbac:groups=monitoring.banzaicloud.io,resources=storeendpoints/status,verbs=get;update;patch 40 | 41 | func (r *StoreEndpointReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 42 | result := ctrl.Result{} 43 | log := r.Log.WithValues("storeendpoint", req.NamespacedName) 44 | 45 | endpoints := &v1alpha1.StoreEndpointList{} 46 | err := r.Client.List(ctx, endpoints) 47 | if err != nil { 48 | if apierrors.IsNotFound(err) { 49 | return result, nil 50 | } 51 | return result, err 52 | } 53 | storeEndpointReconciler := resources.NewStoreEndpointComponentReconciler(endpoints, reconciler.NewGenericReconciler(r.Client, log, reconciler.ReconcilerOpts{})) 54 | 55 | reconcilers := make([]resources.ComponentReconciler, 0) 56 | 57 | // Bucket Web 58 | reconcilers = append(reconcilers, sidecar.New(endpoints, storeEndpointReconciler).Reconcile) 59 | 60 | return resources.RunReconcilers(reconcilers) 61 | } 62 | 63 | func (r *StoreEndpointReconciler) SetupWithManager(mgr ctrl.Manager) error { 64 | return ctrl.NewControllerManagedBy(mgr). 65 | For(&v1alpha1.StoreEndpoint{}). 66 | Owns(&corev1.Service{}). 67 | Owns(&netv1.Ingress{}). 68 | Complete(r) 69 | } 70 | -------------------------------------------------------------------------------- /controllers/suite_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package controllers 16 | 17 | import ( 18 | "os" 19 | "path/filepath" 20 | "testing" 21 | 22 | . "github.com/onsi/ginkgo" 23 | . "github.com/onsi/gomega" 24 | 25 | "github.com/banzaicloud/operator-tools/pkg/utils" 26 | monitoringv1alpha1 "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 27 | "k8s.io/client-go/kubernetes/scheme" 28 | "k8s.io/client-go/rest" 29 | "sigs.k8s.io/controller-runtime/pkg/client" 30 | "sigs.k8s.io/controller-runtime/pkg/envtest" 31 | logf "sigs.k8s.io/controller-runtime/pkg/log" 32 | // +kubebuilder:scaffold:imports 33 | ) 34 | 35 | // These tests use Ginkgo (BDD-style Go testing framework). Refer to 36 | // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 37 | 38 | var cfg *rest.Config 39 | var k8sClient client.Client 40 | var testEnv *envtest.Environment 41 | 42 | func TestAPIs(t *testing.T) { 43 | RegisterFailHandler(Fail) 44 | 45 | RunSpecs(t, "Controller Suite") 46 | } 47 | 48 | var _ = BeforeSuite(func() { 49 | done := make(chan interface{}) 50 | go func() { 51 | defer GinkgoRecover() 52 | defer close(done) 53 | 54 | logf.SetLogger(utils.NewLogger("ginkgo", GinkgoWriter, os.Stderr, 0)) 55 | 56 | By("bootstrapping test environment") 57 | testEnv = &envtest.Environment{ 58 | BinaryAssetsDirectory: os.Getenv("ENVTEST_BINARY_ASSETS"), 59 | CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, 60 | } 61 | 62 | var err error 63 | cfg, err = testEnv.Start() 64 | Expect(err).ToNot(HaveOccurred()) 65 | Expect(cfg).ToNot(BeNil()) 66 | 67 | err = monitoringv1alpha1.AddToScheme(scheme.Scheme) 68 | Expect(err).NotTo(HaveOccurred()) 69 | 70 | err = monitoringv1alpha1.AddToScheme(scheme.Scheme) 71 | Expect(err).NotTo(HaveOccurred()) 72 | 73 | err = monitoringv1alpha1.AddToScheme(scheme.Scheme) 74 | Expect(err).NotTo(HaveOccurred()) 75 | 76 | // +kubebuilder:scaffold:scheme 77 | 78 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) 79 | Expect(err).ToNot(HaveOccurred()) 80 | Expect(k8sClient).ToNot(BeNil()) 81 | }() 82 | Eventually(done, 60).Should(BeClosed()) 83 | }) 84 | 85 | var _ = AfterSuite(func() { 86 | By("tearing down the test environment") 87 | err := testEnv.Stop() 88 | Expect(err).ToNot(HaveOccurred()) 89 | }) 90 | -------------------------------------------------------------------------------- /controllers/thanosendpoint_controller.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package controllers 16 | 17 | import ( 18 | "context" 19 | "strings" 20 | 21 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 22 | "github.com/banzaicloud/thanos-operator/pkg/resources" 23 | "github.com/banzaicloud/thanos-operator/pkg/resources/thanosendpoint" 24 | "github.com/go-logr/logr" 25 | netv1 "k8s.io/api/networking/v1" 26 | apierrors "k8s.io/apimachinery/pkg/api/errors" 27 | "k8s.io/apimachinery/pkg/types" 28 | ctrl "sigs.k8s.io/controller-runtime" 29 | "sigs.k8s.io/controller-runtime/pkg/client" 30 | "sigs.k8s.io/controller-runtime/pkg/handler" 31 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 32 | "sigs.k8s.io/controller-runtime/pkg/source" 33 | 34 | monitoringv1alpha1 "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 35 | ) 36 | 37 | // ThanosEndpointReconciler reconciles a ThanosEndpoint object 38 | type ThanosEndpointReconciler struct { 39 | Client client.Client 40 | Log logr.Logger 41 | } 42 | 43 | // +kubebuilder:rbac:groups=monitoring.banzaicloud.io,resources=thanosendpoints,verbs=get;list;watch;create;update;patch;delete 44 | // +kubebuilder:rbac:groups=monitoring.banzaicloud.io,resources=thanosendpoints/status,verbs=get;update;patch 45 | // +kubebuilder:rbac:groups=integreatly.org,resources=grafanadatasources,verbs=get;list;watch;create;update;patch;delete 46 | 47 | func (r *ThanosEndpointReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 48 | result := ctrl.Result{} 49 | log := r.Log.WithValues("thanosendpoints", req.NamespacedName) 50 | 51 | endpoint := &monitoringv1alpha1.ThanosEndpoint{} 52 | err := r.Client.Get(ctx, req.NamespacedName, endpoint) 53 | if err != nil { 54 | if apierrors.IsNotFound(err) { 55 | return result, nil 56 | } 57 | return result, err 58 | } 59 | 60 | rec := thanosendpoint.NewReconciler(log, r.Client, reconciler.NewReconcilerWith(r.Client), endpoint) 61 | 62 | reconcilers := []resources.ComponentReconciler{ 63 | rec.Reconcile, 64 | } 65 | 66 | return resources.RunReconcilers(reconcilers) 67 | } 68 | 69 | func (r *ThanosEndpointReconciler) SetupWithManager(mgr ctrl.Manager) error { 70 | return ctrl.NewControllerManagedBy(mgr). 71 | For(&monitoringv1alpha1.ThanosEndpoint{}). 72 | Owns(&monitoringv1alpha1.Thanos{}). 73 | Owns(&monitoringv1alpha1.StoreEndpoint{}). 74 | Watches(&source.Kind{Type: &netv1.Ingress{}}, handler.EnqueueRequestsFromMapFunc(func(object client.Object) []reconcile.Request { 75 | ing := object.(*netv1.Ingress) 76 | if ing.Labels != nil { 77 | if mb := ing.Labels[resources.ManagedByLabel]; mb != "" { 78 | return []reconcile.Request{ 79 | { 80 | NamespacedName: types.NamespacedName{ 81 | Name: strings.TrimSuffix(mb, "-endpoint"), 82 | Namespace: ing.Namespace, 83 | }, 84 | }, 85 | } 86 | } 87 | } 88 | return nil 89 | })). 90 | Complete(r) 91 | } 92 | -------------------------------------------------------------------------------- /dashboards/dashboards.md: -------------------------------------------------------------------------------- 1 | # Dashboards 2 | 3 | There exists Grafana dashboards for each component (not all of them complete) targeted for environments running Kubernetes: 4 | 5 | - [Thanos Overview](overview.json) 6 | - [Thanos Compact](compact.json) 7 | - [Thanos Querier](query.json) 8 | - [Thanos Store](store.json) 9 | - [Thanos Receiver](receive.json) 10 | - [Thanos Sidecar](sidecar.json) 11 | - [Thanos Ruler](rule.json) 12 | - [Thanos Replicate](bucket-replicate.json) 13 | 14 | You can import them via `Import -> Paste JSON` in Grafana. 15 | These dashboards require Grafana 5 or above, importing them in older versions are known not to work. 16 | 17 | ## Configuration 18 | 19 | All dashboards are generated using [`thanos-mixin`](https://github.com/thanos-io/thanos/tree/master/mixin/thanos) and check out [README](https://github.com/thanos-io/thanos/tree/master/mixin/thanos/README.md) for further information. 20 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | # Thanos operator Documentation 5 | 6 | Welcome to the Thanos operator documentation! 7 | 8 | 9 | ## Contents 10 | - **[Quickstarts](./quickstarts)** 11 | - [Simple Cluster Thanos](quickstarts/single_cluster_thanos.md) 12 | - **[Custom Resource Definitions (CRD)](./types/Readme.md)** 13 | - [ObjectStoreSpec](./types/objectstore_types.md) 14 | - [StoreEndpointSpec](./types/storeendpoint_types.md) 15 | - [ThanosSpec](./types/thanos_types.md) 16 | - **[Installation](./deploy/README.md)** 17 | - [Deploy with Helm](./deployment.md#deploy-thanos-operator-with-helm) 18 | - **[License](./license.md)** 19 | --- 20 | -------------------------------------------------------------------------------- /docs/architecture.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | # Thanos Operator 5 | 6 | ## Concepts 7 | 8 | ## Custom Resources 9 | 10 | ### ObjectStore 11 | 12 | This resource responsible for operations done per object store. 13 | - Compactor 14 | - Must run 1 instance per bucket 15 | - Responsible for downsampling and compacting 16 | - Bucket 17 | - Reporting tool for buckets 18 | - Simple Web UI 19 | - `config` 20 | - Credential and configuration for object storage 21 | 22 | *example* 23 | ``` 24 | apiVersion: monitoring.banzaicloud.io/v1alpha1 25 | kind: ObjectStore 26 | metadata: 27 | name: objectstore-sample 28 | spec: 29 | config: 30 | mountFrom: 31 | secretKeyRef: 32 | name: thanos 33 | key: object-store.yaml 34 | bucketWeb: {} 35 | compactor: {} 36 | dataVolume: 37 | pvc: 38 | spec: 39 | accessModes: 40 | - ReadWriteOnce 41 | resources: 42 | requests: 43 | storage: 1Gi 44 | ``` 45 | 46 | ### Thanos 47 | 48 | - Query 49 | - HTTP frontend 50 | - StoreGateway 51 | - 52 | - Rule 53 | - 54 | 55 | ### StoreEndpoint 56 | - Define local or remote StoreAPI providers 57 | - Sidecar, Rule, Query, ... 58 | - Local (Selector) or Remote (URL) configuration 59 | - Each `Thanos` and `StoreEndpoint` make a unique Stack with separate instances 60 | 61 | ## Deployment modes -------------------------------------------------------------------------------- /docs/deployment.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | # Requirements 5 | 6 | - Thanos operator requires Kubernetes v1.14.x or later. 7 | - For the [Helm based installation](#deploy-thanos-operator-with-helm) you need Helm v3.0.2 or later. 8 | 9 | 10 | # Deploy Thanos operator with Helm 11 | 12 |

13 |

14 | 15 | Complete the following steps to deploy the Logging operator using Helm. Alternatively, you can also [install the operator using Kubernetes manifests](./Readme.md). 16 | > Note: For the [Helm base installation](#deploy-thanos-operator-with-helm) you need Helm v3 or later. 17 | 18 | 19 | 1. Create `monitor` namespace 20 | ```bash 21 | kubectl create namespace monitor 22 | ``` 23 | 1. Add the operator chart repository. 24 | ```bash 25 | helm repo add banzaicloud-stable https://kubernetes-charts.banzaicloud.com 26 | helm repo update 27 | ``` 28 | 1. Install the Thanos Operator 29 | ```bash 30 | helm install thanos-operator --namespace monitor banzaicloud-stable/thanos-operator 31 | ``` 32 | 33 | --- 34 | 35 | # Check the Thanos operator deployment 36 | 37 | To verify that the installation was successful, complete the following steps. 38 | 39 | 1. Check the status of the pods. You should see a new thanos-operator pod. 40 | ```bash 41 | $ kubectl -n monitor get pods 42 | NAME READY STATUS RESTARTS AGE 43 | thanos-operator-7df8485bf6-gf5gk 1/1 Running 0 13s 44 | ``` 45 | 1. Check the CRDs. You should see the following six new CRDs. 46 | ```bash 47 | $ kubectl get crd 48 | NAME CREATED AT 49 | objectstores.monitoring.banzaicloud.io 2021-04-11T08:38:26Z 50 | receivers.monitoring.banzaicloud.io 2021-04-11T08:38:26Z 51 | storeendpoints.monitoring.banzaicloud.io 2021-04-11T08:38:26Z 52 | thanos.monitoring.banzaicloud.io 2021-04-11T08:38:26Z 53 | thanosendpoints.monitoring.banzaicloud.io 2021-04-11T08:38:27Z 54 | thanospeers.monitoring.banzaicloud.io 2021-04-11T08:38:27Z 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/developers.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | # Developers documentation 5 | 6 | ## Rapid local flow 7 | 8 | This is best used in rapid development workflows, you will need two terminals for this. 9 | 10 | 1. Start thanos-operator locally on your laptop, it will target the current Kubernetes context: 11 | 12 | ```bash 13 | make run 14 | ``` 15 | 16 | 2. In another terminal create a sample Thanos installation with Minio, Prometheus and Thanos CRDs: 17 | 18 | ```bash 19 | make install-thanos 20 | ``` 21 | 22 | 3. Check that Thanos runs properly: 23 | ```bash 24 | kubectl port-forward service/thanos-sample-query 10902 & 25 | open http://localhost:10902/stores 26 | ``` 27 | 28 | ## Containerized flow 29 | 30 | ### Build & Push container 31 | ``` 32 | make docker-build IMG=banzaicloud/thanos-operator:latest 33 | make docker-push IMG=banzaicloud/thanos-operator:latest 34 | ``` 35 | 36 | ### Install operator the cluster 37 | ``` 38 | export KUBECONFIG="" 39 | make install 40 | make deploy IMG=banzaicloud/thanos-operator:latest 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/img/Thanos-multi-cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banzaicloud/thanos-operator/3aa76e5f291768a15a3dcc13099b7c2ad40031ae/docs/img/Thanos-multi-cluster.png -------------------------------------------------------------------------------- /docs/img/Thanos-observer-cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banzaicloud/thanos-operator/3aa76e5f291768a15a3dcc13099b7c2ad40031ae/docs/img/Thanos-observer-cluster.png -------------------------------------------------------------------------------- /docs/img/logo/helm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | logo 10 | Created with Sketch. 11 | 12 | 13 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/img/thanos-single-cluster2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/banzaicloud/thanos-operator/3aa76e5f291768a15a3dcc13099b7c2ad40031ae/docs/img/thanos-single-cluster2.png -------------------------------------------------------------------------------- /docs/license.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | Copyright (c) 2017-2020 [Banzai Cloud, Inc.](https://banzaicloud.com) 4 | 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 | 9 | [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | -------------------------------------------------------------------------------- /docs/quickstarts/README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | ### Thanos Operator quick start guides 5 | 6 | Try out Thanos Operator with these quick start guides! 7 | 8 | 1. [Simple Cluster Thanos](./single_cluster_thanos.md) 9 | -------------------------------------------------------------------------------- /docs/quickstarts/single_cluster_thanos.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | 5 | # Single Cluster Thanos Install 6 | 7 |

8 | 9 | 10 | ## Prerequisites for Thanos 11 | 12 | 1. Create `monitor` namespace 13 | ```bash 14 | kubectl create namespace monitor 15 | ``` 16 | 17 | 1. Create Object Store secret 18 | 19 | Example S3 configuration 20 | ``` 21 | cat <<'EOF' >> object-store.yaml 22 | type: S3 23 | config: 24 | endpoint: "s3.eu-west-1.amazonaws.com" 25 | bucket: "test-bucket" 26 | region: "eu-west-1" 27 | access_key: "XXXXXXXXX" 28 | secret_key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 29 | EOF 30 | ``` 31 | 32 | 1. Deploy the secret on Kubernetes 33 | ``` 34 | kubectl create secret generic thanos --from-file=object-store.yaml=object-store.yaml --namespace monitor 35 | ``` 36 | 37 | 1. Create the Thanos sidecar definition 38 | Extra configuration for prometheus operator. 39 | 40 | > Note: Prometheus-operator and Thanos MUST be in the same namespace. 41 | ``` 42 | cat <<'EOF' >> thanos-sidecar.yaml 43 | prometheus: 44 | prometheusSpec: 45 | thanos: 46 | image: quay.io/thanos/thanos:v0.17.2 47 | version: v0.17.2 48 | objectStorageConfig: 49 | name: thanos 50 | key: object-store.yaml 51 | externalLabels: 52 | cluster: thanos-operator-test 53 | EOF 54 | ``` 55 | 56 | Remember to set `externalLabels` as it identifies the Prometheus instance for Thanos. 57 | 58 | 59 | ## Install the Thanos Operator with Helm 60 | 61 | 62 | 1. Add the Kubernetes stable Helm repository 63 | ``` 64 | helm repo add prometheus-community https://prometheus-community.github.io/helm-charts 65 | helm repo update 66 | ``` 67 | 68 | 1. Install prometheus-operator with the Thanos sidecar 69 | ``` 70 | helm install prometheus-operator --namespace monitor prometheus-community/kube-prometheus-stack -f thanos-sidecar.yaml 71 | ``` 72 | 73 | 1. Add the operator chart repository. 74 | ```bash 75 | helm repo add banzaicloud-stable https://kubernetes-charts.banzaicloud.com 76 | helm repo update 77 | ``` 78 | 1. Install the Thanos Operator 79 | ```bash 80 | helm install thanos-operator --namespace monitor banzaicloud-stable/thanos-operator 81 | ``` 82 | 83 | ## Install the Thanos Operator with the One Eye CLI 84 | 85 | [One Eye](https://banzaicloud.com/docs/one-eye/overview/) will take care of installing and configuring all the dependencies. 86 | 87 | *install the One Eye CLI and deploy the Thanos operator* 88 | ```bash 89 | curl https://getoneeye.sh | sh && one-eye thanos install --prometheus --secret one-eye/object-store.yaml 90 | ``` 91 | 92 | *verify the installation by opening the thanos query page* 93 | ```bash 94 | one-eye thanos connect 95 | ``` 96 | -------------------------------------------------------------------------------- /docs/tls.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | 4 | # Thanos Operator TLS 5 | 6 | To set up secure connection you need to generate your certs. 7 | 8 | example TLS client, server secret 9 | ``` 10 | apiVersion: v1 11 | kind: Secret 12 | type: kubernetes.io/tls 13 | metadata: 14 | name: example-com-server-tls 15 | data: 16 | ca.crt: xxx 17 | tls.crt: xxx 18 | tls.key: xxx 19 | ``` -------------------------------------------------------------------------------- /docs/types/Readme.md: -------------------------------------------------------------------------------- 1 | # Available Types 2 | 3 | For more information please click on the name 4 |

5 | 6 | | Name | Description | 7 | |---|---| 8 | | **[ObjectStoreSpec](objectstore_types.md)** | | 9 | | **[ReceiverSpec](receiver_types.md)** | | 10 | | **[StoreEndpointSpec](storeendpoint_types.md)** | | 11 | | **[ThanosSpec](thanos_types.md)** | | 12 | | **[ThanosEndpoint](thanosendpoint_types.md)** | | 13 | | **[ThanosPeer](thanospeer_types.md)** | | 14 |
15 | 16 | -------------------------------------------------------------------------------- /docs/types/storeendpoint_types.md: -------------------------------------------------------------------------------- 1 | ## StoreEndpointSpec 2 | 3 | StoreEndpointSpec defines the desired state of StoreEndpoint 4 | 5 | ### metaOverrides (*typeoverride.ObjectMeta, optional) {#storeendpointspec-metaoverrides} 6 | 7 | See [ObjectMeta override](../overrides/override/#objectmeta) 8 | 9 | Default: - 10 | 11 | ### serviceOverrides (*typeoverride.Service, optional) {#storeendpointspec-serviceoverrides} 12 | 13 | See [Service override](../overrides/override/#service) 14 | 15 | Default: - 16 | 17 | ### url (string, optional) {#storeendpointspec-url} 18 | 19 | Default: - 20 | 21 | ### selector (*KubernetesSelector, optional) {#storeendpointspec-selector} 22 | 23 | See [KubernetesSelector](#kubernetesselector) 24 | 25 | Default: - 26 | 27 | ### config (secret.Secret, optional) {#storeendpointspec-config} 28 | 29 | Default: - 30 | 31 | ### thanos (string, required) {#storeendpointspec-thanos} 32 | 33 | Default: - 34 | 35 | ### ingress (*Ingress, optional) {#storeendpointspec-ingress} 36 | 37 | Default: - 38 | 39 | 40 | ## KubernetesSelector 41 | 42 | ### namespaces (string, optional) {#kubernetesselector-namespaces} 43 | 44 | Default: - 45 | 46 | ### labels (map[string]string, optional) {#kubernetesselector-labels} 47 | 48 | Default: - 49 | 50 | ### annotations (map[string]string, optional) {#kubernetesselector-annotations} 51 | 52 | Default: - 53 | 54 | ### httpPort (int32, optional) {#kubernetesselector-httpport} 55 | 56 | Default: - 57 | 58 | ### grpcPort (int32, optional) {#kubernetesselector-grpcport} 59 | 60 | Default: - 61 | 62 | 63 | ## StoreEndpointStatus 64 | 65 | StoreEndpointStatus defines the observed state of StoreEndpoint 66 | 67 | 68 | ## StoreEndpoint 69 | 70 | StoreEndpoint is the Schema for the storeendpoints API 71 | 72 | ### (metav1.TypeMeta, required) {#storeendpoint-} 73 | 74 | Default: - 75 | 76 | ### metadata (metav1.ObjectMeta, optional) {#storeendpoint-metadata} 77 | 78 | Default: - 79 | 80 | ### spec (StoreEndpointSpec, optional) {#storeendpoint-spec} 81 | 82 | See [StoreEndpointSpec](#storeendpointspec) 83 | 84 | Default: - 85 | 86 | ### status (StoreEndpointStatus, optional) {#storeendpoint-status} 87 | 88 | See [StoreEndpointStatus](#storeendpointstatus) 89 | 90 | Default: - 91 | 92 | 93 | ## StoreEndpointList 94 | 95 | StoreEndpointList contains a list of StoreEndpoint 96 | 97 | ### (metav1.TypeMeta, required) {#storeendpointlist-} 98 | 99 | Default: - 100 | 101 | ### metadata (metav1.ListMeta, optional) {#storeendpointlist-metadata} 102 | 103 | Default: - 104 | 105 | ### items ([]StoreEndpoint, required) {#storeendpointlist-items} 106 | 107 | Default: - 108 | 109 | 110 | -------------------------------------------------------------------------------- /docs/types/thanosendpoint_types.md: -------------------------------------------------------------------------------- 1 | ## ThanosEndpoint 2 | 3 | ### (metav1.TypeMeta, required) {#thanosendpoint-} 4 | 5 | Default: - 6 | 7 | ### metadata (metav1.ObjectMeta, optional) {#thanosendpoint-metadata} 8 | 9 | Default: - 10 | 11 | ### spec (ThanosEndpointSpec, optional) {#thanosendpoint-spec} 12 | 13 | See [ThanosEndpointSpec](#thanosendpointspec) 14 | 15 | Default: - 16 | 17 | ### status (ThanosEndpointStatus, optional) {#thanosendpoint-status} 18 | 19 | See [ThanosEndpointStatus](#thanosendpointstatus) 20 | 21 | Default: - 22 | 23 | 24 | ## ThanosEndpointList 25 | 26 | ### (metav1.TypeMeta, required) {#thanosendpointlist-} 27 | 28 | Default: - 29 | 30 | ### metadata (metav1.ListMeta, optional) {#thanosendpointlist-metadata} 31 | 32 | Default: - 33 | 34 | ### items ([]ThanosEndpoint, required) {#thanosendpointlist-items} 35 | 36 | Default: - 37 | 38 | 39 | ## ThanosEndpointSpec 40 | 41 | ### certificate (string, optional) {#thanosendpointspec-certificate} 42 | 43 | The endpoint should use this server certificate (tls.crt, tls.key) in the current namespace 44 | 45 | Default: - 46 | 47 | ### ingressClassName (string, optional) {#thanosendpointspec-ingressclassname} 48 | 49 | Reference the given ingressClass resource explicitly 50 | 51 | Default: - 52 | 53 | ### caBundle (string, optional) {#thanosendpointspec-cabundle} 54 | 55 | Name of the secret that contains the CA certificate in ca.crt to verify client certs in the current namespace 56 | 57 | Default: - 58 | 59 | ### stores ([]string, optional) {#thanosendpointspec-stores} 60 | 61 | List of statically configured store addresses 62 | 63 | Default: - 64 | 65 | ### replicaLabels ([]string, optional) {#thanosendpointspec-replicalabels} 66 | 67 | Custom replica labels if the default doesn't apply 68 | 69 | Default: - 70 | 71 | ### metaOverrides (typeoverride.ObjectMeta, optional) {#thanosendpointspec-metaoverrides} 72 | 73 | [Override metadata](../overrides/override/#objectmeta) for managed resources 74 | 75 | Default: - 76 | 77 | ### queryOverrides (*Query, optional) {#thanosendpointspec-queryoverrides} 78 | 79 | Override any of the [Query parameters](../thanos_types/#query) 80 | 81 | Default: - 82 | 83 | ### storeEndpointOverrides ([]StoreEndpointSpec, optional) {#thanosendpointspec-storeendpointoverrides} 84 | 85 | Override any of the [StoreEndpoint parameters](../storeendpoint_types/) 86 | 87 | Default: - 88 | 89 | 90 | ## ThanosEndpointStatus 91 | 92 | ### endpointAddress (string, optional) {#thanosendpointstatus-endpointaddress} 93 | 94 | Host (or IP) and port of the exposed Thanos endpoint 95 | 96 | Default: - 97 | 98 | 99 | -------------------------------------------------------------------------------- /docs/types/thanospeer_types.md: -------------------------------------------------------------------------------- 1 | ## ThanosPeer 2 | 3 | ### (metav1.TypeMeta, required) {#thanospeer-} 4 | 5 | Default: - 6 | 7 | ### metadata (metav1.ObjectMeta, optional) {#thanospeer-metadata} 8 | 9 | Default: - 10 | 11 | ### spec (ThanosPeerSpec, optional) {#thanospeer-spec} 12 | 13 | See [ThanosPeerSpec](#thanospeerspec) 14 | 15 | Default: - 16 | 17 | ### status (ThanosPeerStatus, optional) {#thanospeer-status} 18 | 19 | See [ThanosPeerStatus](#thanospeerstatus) 20 | 21 | Default: - 22 | 23 | 24 | ## ThanosPeerList 25 | 26 | ### (metav1.TypeMeta, required) {#thanospeerlist-} 27 | 28 | Default: - 29 | 30 | ### metadata (metav1.ListMeta, optional) {#thanospeerlist-metadata} 31 | 32 | Default: - 33 | 34 | ### items ([]ThanosPeer, required) {#thanospeerlist-items} 35 | 36 | Default: - 37 | 38 | 39 | ## ThanosPeerSpec 40 | 41 | ### endpointAddress (string, required) {#thanospeerspec-endpointaddress} 42 | 43 | Host (or IP) and port of the remote Thanos endpoint 44 | 45 | Default: - 46 | 47 | ### peerEndpointAlias (string, optional) {#thanospeerspec-peerendpointalias} 48 | 49 | Optional alias for the remote endpoint in case we have to access it through a different name. This is typically needed if the remote endpoint has a certificate created for a predefined hostname. The controller should create an externalName service for this backed buy the actual peer endpoint host or a k8s service with a manually crafted k8s endpoint if EndpointAddress doesn't have a host but only an IP. 50 | 51 | Default: - 52 | 53 | ### certificate (string, optional) {#thanospeerspec-certificate} 54 | 55 | The peer query should use this client certificate (tls.crt, tls.key) in the current namespace 56 | 57 | Default: - 58 | 59 | ### caBundle (string, optional) {#thanospeerspec-cabundle} 60 | 61 | Name of the secret that contains the CA certificate in ca.crt to verify client certs in the current namespace 62 | 63 | Default: - 64 | 65 | ### replicaLabels ([]string, optional) {#thanospeerspec-replicalabels} 66 | 67 | Custom replica labels if the default doesn't apply 68 | 69 | Default: - 70 | 71 | ### metaOverrides (typeoverride.ObjectMeta, optional) {#thanospeerspec-metaoverrides} 72 | 73 | [Override metadata](../overrides/override/#objectmeta) for managed resources 74 | 75 | Default: - 76 | 77 | ### queryOverrides (*Query, optional) {#thanospeerspec-queryoverrides} 78 | 79 | Override any of the [Query parameters](../thanos_types/#query) 80 | 81 | Default: - 82 | 83 | 84 | ## ThanosPeerStatus 85 | 86 | ### queryHTTPServiceURL (string, optional) {#thanospeerstatus-queryhttpserviceurl} 87 | 88 | The peer query is available over HTTP on this internal service URL 89 | 90 | Default: - 91 | 92 | 93 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. -------------------------------------------------------------------------------- /hack/grpc-ingress-mtls.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # start a cluster on aws 3 | 4 | # install cert-manager 5 | 6 | kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager.yaml 7 | 8 | # nginx ingress 9 | 10 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.44.0/deploy/static/provider/cloud/deploy.yaml 11 | 12 | # install minio and prometheus 13 | 14 | kubectl get service prometheus-operated || one-eye prometheus install --update --accept-license 15 | 16 | # start the thanos operator on demand in a separate shell 17 | 18 | make run & 19 | trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT 20 | 21 | # we need an alias to the endpoint to generate the cert with 22 | export PEER_ENDPOINT=peer 23 | 24 | # create a selfsigned CA and a cert for communication 25 | cat < certs/observer/ca.crt 91 | kubectl view-secret observer-tls tls.crt > certs/observer/tls.crt 92 | kubectl view-secret observer-tls tls.key > certs/observer/tls.key 93 | 94 | kubectl view-secret observer-tls ca.crt > certs/peer/ca.crt 95 | kubectl view-secret peer-tls tls.crt > certs/peer/tls.crt 96 | kubectl view-secret peer-tls tls.key > certs/peer/tls.key 97 | 98 | kubectl create secret generic peer-tls-with-observer-ca --from-file certs/peer 99 | kubectl create secret generic observer-tls-with-peer-ca --from-file certs/observer 100 | 101 | # Aggregator query 102 | cat < 0 { 26 | _, _ = b.WriteString("-") 27 | } 28 | _, _ = b.WriteString(part) 29 | } 30 | return b.String() 31 | } 32 | -------------------------------------------------------------------------------- /pkg/resources/compactor/compactor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package compactor 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/utils" 19 | "github.com/banzaicloud/thanos-operator/pkg/resources" 20 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 21 | "github.com/imdario/mergo" 22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 24 | ) 25 | 26 | const Name = "compactor" 27 | 28 | type Compactor struct { 29 | *resources.ObjectStoreReconciler 30 | } 31 | 32 | func New(reconciler *resources.ObjectStoreReconciler) *Compactor { 33 | return &Compactor{ 34 | ObjectStoreReconciler: reconciler, 35 | } 36 | } 37 | 38 | func (c *Compactor) Reconcile() (*reconcile.Result, error) { 39 | if c.ObjectStore.Spec.Compactor != nil { 40 | err := mergo.Merge(c.ObjectStore.Spec.Compactor, v1alpha1.DefaultCompactor) 41 | if err != nil { 42 | return nil, err 43 | } 44 | } 45 | return c.ReconcileResources([]resources.Resource{ 46 | //c.persistentVolumeClaim, 47 | c.deployment, 48 | c.service, 49 | c.serviceMonitor, 50 | c.persistentVolumeClaim, 51 | }) 52 | } 53 | 54 | func (c *Compactor) getName() string { 55 | return c.QualifiedName(Name) 56 | } 57 | 58 | func (c *Compactor) getLabels() resources.Labels { 59 | return utils.MergeLabels( 60 | resources.Labels{ 61 | resources.NameLabel: c.getName(), 62 | }, 63 | c.GetCommonLabels(), 64 | ) 65 | } 66 | 67 | func (c *Compactor) getMeta() metav1.ObjectMeta { 68 | meta := c.GetObjectMeta(c.getName()) 69 | meta.Labels = c.getLabels() 70 | return meta 71 | } 72 | -------------------------------------------------------------------------------- /pkg/resources/compactor/persistentvolumeclaim.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package compactor 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | corev1 "k8s.io/api/core/v1" 20 | "k8s.io/apimachinery/pkg/runtime" 21 | ) 22 | 23 | func (c *Compactor) persistentVolumeClaim() (runtime.Object, reconciler.DesiredState, error) { 24 | meta := c.getMeta() 25 | if c.ObjectStore.Spec.Compactor != nil && 26 | c.ObjectStore.Spec.Compactor.DataVolume != nil && 27 | c.ObjectStore.Spec.Compactor.DataVolume.PersistentVolumeClaim != nil && 28 | c.ObjectStore.Spec.Compactor.DataVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName == "" { 29 | compactor := c.ObjectStore.Spec.Compactor 30 | pvc := &corev1.PersistentVolumeClaim{ 31 | ObjectMeta: compactor.MetaOverrides.Merge(meta), 32 | Spec: c.ObjectStore.Spec.Compactor.DataVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec, 33 | } 34 | return pvc, reconciler.StatePresent, nil 35 | } 36 | 37 | pvc := &corev1.PersistentVolumeClaim{ 38 | ObjectMeta: meta, 39 | } 40 | return pvc, reconciler.StateAbsent, nil 41 | } 42 | -------------------------------------------------------------------------------- /pkg/resources/compactor/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package compactor 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | corev1 "k8s.io/api/core/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/util/intstr" 25 | ) 26 | 27 | func (c *Compactor) service() (runtime.Object, reconciler.DesiredState, error) { 28 | if c.ObjectStore.Spec.Compactor != nil { 29 | compactor := c.ObjectStore.Spec.Compactor 30 | service := &corev1.Service{ 31 | ObjectMeta: compactor.MetaOverrides.Merge(c.getMeta()), 32 | Spec: corev1.ServiceSpec{ 33 | Ports: []corev1.ServicePort{ 34 | { 35 | Protocol: corev1.ProtocolTCP, 36 | Name: "http", 37 | Port: resources.GetPort(compactor.HTTPAddress), 38 | TargetPort: intstr.FromInt(int(resources.GetPort(compactor.HTTPAddress))), 39 | }, 40 | }, 41 | Selector: c.getLabels(), 42 | }, 43 | } 44 | 45 | if compactor.ServiceOverrides != nil { 46 | err := merge.Merge(service, compactor.ServiceOverrides) 47 | if err != nil { 48 | return service, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to service base") 49 | } 50 | } 51 | 52 | return service, reconciler.DesiredStateHook(func(current runtime.Object) error { 53 | if s, ok := current.(*corev1.Service); ok { 54 | service.Spec.ClusterIP = s.Spec.ClusterIP 55 | } else { 56 | return errors.Errorf("failed to cast service object %+v", current) 57 | } 58 | return nil 59 | }), nil 60 | } 61 | 62 | return &corev1.Service{ 63 | ObjectMeta: c.getMeta(), 64 | }, reconciler.StateAbsent, nil 65 | } 66 | -------------------------------------------------------------------------------- /pkg/resources/compactor/servicemonitor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package compactor 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | prometheus "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" 20 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | ) 23 | 24 | func (c *Compactor) serviceMonitor() (runtime.Object, reconciler.DesiredState, error) { 25 | if c.ObjectStore.Spec.Compactor != nil && c.ObjectStore.Spec.Compactor.Metrics.ServiceMonitor { 26 | metrics := c.ObjectStore.Spec.Compactor.Metrics 27 | meta := c.getMeta() 28 | compactor := c.ObjectStore.Spec.Compactor.DeepCopy() 29 | serviceMonitor := &prometheus.ServiceMonitor{ 30 | ObjectMeta: compactor.MetaOverrides.Merge(meta), 31 | Spec: prometheus.ServiceMonitorSpec{ 32 | Endpoints: []prometheus.Endpoint{ 33 | { 34 | Port: "http", 35 | Path: metrics.Path, 36 | Interval: metrics.Interval, 37 | ScrapeTimeout: metrics.Timeout, 38 | }, 39 | }, 40 | Selector: v1.LabelSelector{ 41 | MatchLabels: c.getLabels(), 42 | }, 43 | NamespaceSelector: prometheus.NamespaceSelector{ 44 | MatchNames: []string{ 45 | c.ObjectStore.Namespace, 46 | }, 47 | }, 48 | SampleLimit: 0, 49 | }, 50 | } 51 | return serviceMonitor, reconciler.StatePresent, nil 52 | } 53 | delete := &prometheus.ServiceMonitor{ 54 | ObjectMeta: c.getMeta(), 55 | } 56 | return delete, reconciler.StateAbsent, nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/resources/componentreconciler.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package resources 16 | 17 | import ( 18 | ctrl "sigs.k8s.io/controller-runtime" 19 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 20 | ) 21 | 22 | // RunReconcilers run component reconcilers one by one and stop on first error. 23 | func RunReconcilers(reconcilers []ComponentReconciler) (ctrl.Result, error) { 24 | for _, reconciler := range reconcilers { 25 | result, err := reconciler() 26 | if err != nil { 27 | return reconcile.Result{}, err 28 | } 29 | if result != nil { 30 | // short circuit if requested explicitly 31 | return *result, nil 32 | } 33 | } 34 | 35 | return ctrl.Result{}, nil 36 | } 37 | -------------------------------------------------------------------------------- /pkg/resources/objectstore.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package resources 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/operator-tools/pkg/utils" 22 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 25 | ) 26 | 27 | type ObjectStoreReconciler struct { 28 | ObjectStore *v1alpha1.ObjectStore 29 | *reconciler.GenericResourceReconciler 30 | } 31 | 32 | func (t *ObjectStoreReconciler) GetCommonLabels() Labels { 33 | return Labels{ 34 | ManagedByLabel: t.ObjectStore.Name, 35 | } 36 | } 37 | 38 | func (t *ObjectStoreReconciler) QualifiedName(name string) string { 39 | return fmt.Sprintf("%s-%s", t.ObjectStore.Name, name) 40 | } 41 | 42 | func (t *ObjectStoreReconciler) GetObjectMeta(name string) metav1.ObjectMeta { 43 | return metav1.ObjectMeta{ 44 | Name: name, 45 | Namespace: t.ObjectStore.Namespace, 46 | OwnerReferences: []metav1.OwnerReference{ 47 | { 48 | APIVersion: t.ObjectStore.APIVersion, 49 | Kind: t.ObjectStore.Kind, 50 | Name: t.ObjectStore.Name, 51 | UID: t.ObjectStore.UID, 52 | Controller: utils.BoolPointer(true), 53 | }, 54 | }, 55 | } 56 | } 57 | 58 | func (t *ObjectStoreReconciler) ReconcileResources(resourceList []Resource) (*reconcile.Result, error) { 59 | return Dispatch(t.GenericResourceReconciler, resourceList) 60 | } 61 | 62 | func NewObjectStoreReconciler(objectStore *v1alpha1.ObjectStore, genericReconciler *reconciler.GenericResourceReconciler) *ObjectStoreReconciler { 63 | return &ObjectStoreReconciler{ 64 | ObjectStore: objectStore, 65 | GenericResourceReconciler: genericReconciler, 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pkg/resources/query/grafanadatasource.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package query 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | "github.com/banzaicloud/operator-tools/pkg/utils" 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 22 | "k8s.io/apimachinery/pkg/runtime" 23 | ) 24 | 25 | type strIfMap = map[string]interface{} 26 | 27 | func (q *Query) grafanaDatasource() (runtime.Object, reconciler.DesiredState, error) { 28 | 29 | grafanaDatasource := unstructured.Unstructured{} 30 | grafanaDatasource.SetAPIVersion("integreatly.org/v1alpha1") 31 | grafanaDatasource.SetKind("GrafanaDataSource") 32 | 33 | grafanaDatasource.SetName(q.getName()) 34 | grafanaDatasource.SetNamespace(q.Thanos.Namespace) 35 | 36 | state := reconciler.StatePresent 37 | if q.Thanos.Spec.Query == nil || !q.Thanos.Spec.Query.GrafanaDatasource { 38 | return &grafanaDatasource, reconciler.StateAbsent, nil 39 | } 40 | 41 | grafanaDatasource.SetOwnerReferences([]metav1.OwnerReference{ 42 | { 43 | APIVersion: q.Thanos.APIVersion, 44 | Kind: q.Thanos.Kind, 45 | Name: q.Thanos.Name, 46 | UID: q.Thanos.UID, 47 | Controller: utils.BoolPointer(true), 48 | }, 49 | }) 50 | 51 | grafanaDatasource.SetLabels(q.GetCommonLabels()) 52 | 53 | grafanaDatasource.Object["spec"] = strIfMap{ 54 | "datasources": []strIfMap{ 55 | { 56 | "access": "proxy", 57 | "editable": true, 58 | "isDefault": false, 59 | "name": q.getName(), 60 | "type": "prometheus", 61 | "url": q.GetHTTPServiceURL(), 62 | "version": 1, 63 | }, 64 | }, 65 | "name": q.getName(), 66 | } 67 | 68 | return &grafanaDatasource, state, nil 69 | } 70 | -------------------------------------------------------------------------------- /pkg/resources/query/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package query 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | corev1 "k8s.io/api/core/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/util/intstr" 25 | ) 26 | 27 | func (q *Query) service() (runtime.Object, reconciler.DesiredState, error) { 28 | if q.Thanos.Spec.Query != nil { 29 | queryService := &corev1.Service{ 30 | ObjectMeta: q.Thanos.Spec.Query.MetaOverrides.Merge(q.getMeta(q.getName())), 31 | Spec: corev1.ServiceSpec{ 32 | Ports: []corev1.ServicePort{ 33 | { 34 | Name: "grpc", 35 | Protocol: corev1.ProtocolTCP, 36 | Port: resources.GetPort(q.Thanos.Spec.Query.GRPCAddress), 37 | TargetPort: intstr.FromString("grpc"), 38 | }, 39 | { 40 | Name: "http", 41 | Protocol: corev1.ProtocolTCP, 42 | Port: resources.GetPort(q.Thanos.Spec.Query.HttpAddress), 43 | TargetPort: intstr.FromString("http"), 44 | }, 45 | }, 46 | Selector: q.getLabels(), 47 | Type: corev1.ServiceTypeClusterIP, 48 | }, 49 | } 50 | 51 | if q.Thanos.Spec.Query.ServiceOverrides != nil { 52 | err := merge.Merge(queryService, q.Thanos.Spec.Query.ServiceOverrides) 53 | if err != nil { 54 | return queryService, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 55 | } 56 | } 57 | 58 | return queryService, reconciler.DesiredStateHook(func(current runtime.Object) error { 59 | if s, ok := current.(*corev1.Service); ok { 60 | queryService.Spec.ClusterIP = s.Spec.ClusterIP 61 | } else { 62 | return errors.Errorf("failed to cast service object %+v", current) 63 | } 64 | return nil 65 | }), nil 66 | } 67 | delete := &corev1.Service{ 68 | ObjectMeta: q.getMeta(q.getName()), 69 | } 70 | return delete, reconciler.StateAbsent, nil 71 | } 72 | -------------------------------------------------------------------------------- /pkg/resources/query/servicemonitor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package query 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | prometheus "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" 20 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | ) 23 | 24 | func (q *Query) serviceMonitor() (runtime.Object, reconciler.DesiredState, error) { 25 | if q.Thanos.Spec.Query != nil && q.Thanos.Spec.Query.Metrics.ServiceMonitor { 26 | metrics := q.Thanos.Spec.Query.Metrics 27 | serviceMonitor := &prometheus.ServiceMonitor{ 28 | ObjectMeta: q.Thanos.Spec.Query.MetaOverrides.Merge(q.getMeta(q.getName())), 29 | Spec: prometheus.ServiceMonitorSpec{ 30 | Endpoints: []prometheus.Endpoint{ 31 | { 32 | Port: "http", 33 | Path: metrics.Path, 34 | Interval: metrics.Interval, 35 | ScrapeTimeout: metrics.Timeout, 36 | }, 37 | }, 38 | Selector: v1.LabelSelector{ 39 | MatchLabels: q.getLabels(), 40 | }, 41 | NamespaceSelector: prometheus.NamespaceSelector{ 42 | MatchNames: []string{ 43 | q.Thanos.Namespace, 44 | }, 45 | }, 46 | SampleLimit: 0, 47 | }, 48 | } 49 | return serviceMonitor, reconciler.StatePresent, nil 50 | } 51 | delete := &prometheus.ServiceMonitor{ 52 | ObjectMeta: q.getMeta(q.getName()), 53 | } 54 | return delete, reconciler.StateAbsent, nil 55 | } 56 | -------------------------------------------------------------------------------- /pkg/resources/query_frontend/deployment.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package query_frontend 16 | 17 | import ( 18 | "fmt" 19 | 20 | "emperror.dev/errors" 21 | "github.com/banzaicloud/operator-tools/pkg/merge" 22 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 23 | "github.com/banzaicloud/operator-tools/pkg/utils" 24 | "github.com/banzaicloud/thanos-operator/pkg/resources" 25 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 26 | appsv1 "k8s.io/api/apps/v1" 27 | corev1 "k8s.io/api/core/v1" 28 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 | "k8s.io/apimachinery/pkg/runtime" 30 | ) 31 | 32 | func (q *QueryFrontend) deployment() (runtime.Object, reconciler.DesiredState, error) { 33 | if q.Thanos.Spec.QueryFrontend != nil { 34 | queryFrontend := q.Thanos.Spec.QueryFrontend 35 | 36 | deployment := &appsv1.Deployment{ 37 | ObjectMeta: queryFrontend.MetaOverrides.Merge(q.getMeta(q.getName())), 38 | Spec: appsv1.DeploymentSpec{ 39 | Replicas: utils.IntPointer(1), 40 | Selector: &metav1.LabelSelector{ 41 | MatchLabels: q.getLabels(), 42 | }, 43 | Template: corev1.PodTemplateSpec{ 44 | ObjectMeta: q.getMeta(q.getName()), 45 | Spec: corev1.PodSpec{ 46 | Containers: []corev1.Container{ 47 | { 48 | Name: "query-frontend", 49 | Image: fmt.Sprintf("%s:%s", v1alpha1.ThanosImageRepository, v1alpha1.ThanosImageTag), 50 | Args: []string{ 51 | "query-frontend", 52 | }, 53 | Ports: []corev1.ContainerPort{ 54 | { 55 | Name: "http", 56 | ContainerPort: resources.GetPort(queryFrontend.HttpAddress), 57 | Protocol: corev1.ProtocolTCP, 58 | }, 59 | }, 60 | ImagePullPolicy: corev1.PullIfNotPresent, 61 | LivenessProbe: resources.GetProbe(resources.GetPort(queryFrontend.HttpAddress), resources.HealthCheckPath), 62 | ReadinessProbe: resources.GetProbe(resources.GetPort(queryFrontend.HttpAddress), resources.ReadyCheckPath), 63 | }, 64 | }, 65 | }, 66 | }, 67 | }, 68 | } 69 | 70 | // Set up args 71 | deployment.Spec.Template.Spec.Containers[0].Args = q.setArgs(deployment.Spec.Template.Spec.Containers[0].Args) 72 | 73 | if queryFrontend.DeploymentOverrides != nil { 74 | if err := merge.Merge(deployment, queryFrontend.DeploymentOverrides); err != nil { 75 | return deployment, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 76 | } 77 | } 78 | 79 | return deployment, reconciler.StatePresent, nil 80 | } 81 | delete := &appsv1.Deployment{ 82 | ObjectMeta: q.getMeta(q.getName()), 83 | } 84 | return delete, reconciler.StateAbsent, nil 85 | } 86 | -------------------------------------------------------------------------------- /pkg/resources/query_frontend/ingress.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package query_frontend 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | corev1 "k8s.io/api/core/v1" 22 | netv1 "k8s.io/api/networking/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | ) 25 | 26 | func (q *QueryFrontend) ingressHTTP() (runtime.Object, reconciler.DesiredState, error) { 27 | if q.Thanos.Spec.QueryFrontend != nil && 28 | q.Thanos.Spec.QueryFrontend.HTTPIngress != nil { 29 | queryFrontendIngress := q.Thanos.Spec.QueryFrontend.HTTPIngress 30 | queryFrontend := q.Thanos.Spec.QueryFrontend 31 | pathType := netv1.PathTypeImplementationSpecific 32 | ingress := &netv1.Ingress{ 33 | ObjectMeta: queryFrontend.MetaOverrides.Merge(q.getMeta(q.getName("http"))), 34 | Spec: netv1.IngressSpec{ 35 | Rules: []netv1.IngressRule{ 36 | { 37 | Host: queryFrontendIngress.Host, 38 | IngressRuleValue: netv1.IngressRuleValue{ 39 | HTTP: &netv1.HTTPIngressRuleValue{ 40 | Paths: []netv1.HTTPIngressPath{ 41 | { 42 | Path: queryFrontendIngress.Path, 43 | PathType: &pathType, 44 | Backend: netv1.IngressBackend{ 45 | Service: &netv1.IngressServiceBackend{ 46 | Name: q.getName(), 47 | Port: netv1.ServiceBackendPort{ 48 | Name: "http", 49 | }, 50 | }, 51 | }, 52 | }, 53 | }, 54 | }, 55 | }, 56 | }, 57 | }, 58 | }, 59 | } 60 | if queryFrontendIngress.Certificate != "" { 61 | ingress.Spec.TLS = []netv1.IngressTLS{ 62 | { 63 | Hosts: []string{queryFrontendIngress.Host}, 64 | SecretName: queryFrontendIngress.Certificate, 65 | }, 66 | } 67 | } 68 | 69 | if queryFrontendIngress.IngressOverrides != nil { 70 | err := merge.Merge(ingress, queryFrontendIngress.IngressOverrides) 71 | if err != nil { 72 | return ingress, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 73 | } 74 | } 75 | 76 | return ingress, reconciler.StatePresent, nil 77 | } 78 | delete := &corev1.Service{ 79 | ObjectMeta: q.getMeta(q.getName("http")), 80 | } 81 | return delete, reconciler.StateAbsent, nil 82 | } 83 | -------------------------------------------------------------------------------- /pkg/resources/query_frontend/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package query_frontend 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | corev1 "k8s.io/api/core/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/util/intstr" 25 | ) 26 | 27 | func (q *QueryFrontend) service() (runtime.Object, reconciler.DesiredState, error) { 28 | if q.Thanos.Spec.QueryFrontend != nil { 29 | queryFrontend := q.Thanos.Spec.QueryFrontend 30 | queryService := &corev1.Service{ 31 | ObjectMeta: queryFrontend.MetaOverrides.Merge(q.getMeta(q.getName())), 32 | Spec: corev1.ServiceSpec{ 33 | Ports: []corev1.ServicePort{ 34 | { 35 | Name: "http", 36 | Protocol: corev1.ProtocolTCP, 37 | Port: resources.GetPort(queryFrontend.HttpAddress), 38 | TargetPort: intstr.FromString("http"), 39 | }, 40 | }, 41 | Selector: q.getLabels(), 42 | Type: corev1.ServiceTypeClusterIP, 43 | }, 44 | } 45 | 46 | if queryFrontend.ServiceOverrides != nil { 47 | err := merge.Merge(queryService, queryFrontend.ServiceOverrides) 48 | if err != nil { 49 | return queryService, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 50 | } 51 | } 52 | 53 | return queryService, reconciler.StatePresent, nil 54 | } 55 | delete := &corev1.Service{ 56 | ObjectMeta: q.getMeta(q.getName()), 57 | } 58 | return delete, reconciler.StateAbsent, nil 59 | } 60 | -------------------------------------------------------------------------------- /pkg/resources/receiver/component.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package receiver 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | monitoringv1alpha1 "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 20 | "github.com/imdario/mergo" 21 | prometheus "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" 22 | appsv1 "k8s.io/api/apps/v1" 23 | corev1 "k8s.io/api/core/v1" 24 | netv1 "k8s.io/api/networking/v1" 25 | "k8s.io/apimachinery/pkg/runtime" 26 | "k8s.io/apimachinery/pkg/runtime/schema" 27 | "sigs.k8s.io/controller-runtime/pkg/builder" 28 | "sigs.k8s.io/controller-runtime/pkg/client/apiutil" 29 | ) 30 | 31 | func NewComponent(scheme *runtime.Scheme) *Component { 32 | objects := []runtime.Object{ 33 | &appsv1.StatefulSet{}, 34 | &corev1.Service{}, 35 | &prometheus.ServiceMonitor{}, 36 | &netv1.Ingress{}, 37 | } 38 | 39 | purgeTypes := make([]schema.GroupVersionKind, 0, len(objects)) 40 | for _, obj := range objects { 41 | gvk, err := apiutil.GVKForObject(obj, scheme) 42 | if err != nil { 43 | panic(err) 44 | } 45 | purgeTypes = append(purgeTypes, gvk) 46 | } 47 | 48 | return &Component{ 49 | purgeTypes: purgeTypes, 50 | } 51 | } 52 | 53 | type Component struct { 54 | purgeTypes []schema.GroupVersionKind 55 | } 56 | 57 | func (Component) ResourceBuilders(parent reconciler.ResourceOwner, config interface{}) (builders []reconciler.ResourceBuilder) { 58 | receiver, _ := parent.(*monitoringv1alpha1.Receiver) 59 | if receiver == nil { 60 | return 61 | } 62 | 63 | r := extend(receiver) 64 | builders = append(builders, 65 | r.commonService, 66 | r.hashringConfig, 67 | ) 68 | 69 | for _, group := range receiver.Spec.ReceiverGroups { 70 | group := group 71 | if err := mergo.Merge(&group, monitoringv1alpha1.DefaultReceiverGroup); err != nil { 72 | return 73 | } 74 | g := receiverInstance{r, &group} 75 | builders = append(builders, 76 | g.statefulset, 77 | g.service, 78 | g.serviceMonitor, 79 | g.ingressGRPC, 80 | g.ingressHTTP, 81 | ) 82 | } 83 | 84 | return 85 | } 86 | 87 | func (Component) RegisterWatches(b *builder.Builder) { 88 | b.For(&monitoringv1alpha1.Receiver{}). 89 | Owns(&corev1.Service{}). 90 | Owns(&netv1.Ingress{}). 91 | Owns(&appsv1.StatefulSet{}). 92 | Owns(&corev1.ConfigMap{}) 93 | } 94 | 95 | func (c Component) PurgeTypes() []schema.GroupVersionKind { 96 | return append([]schema.GroupVersionKind(nil), c.purgeTypes...) 97 | } 98 | -------------------------------------------------------------------------------- /pkg/resources/receiver/hashring.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package receiver 16 | 17 | import ( 18 | "encoding/json" 19 | "fmt" 20 | 21 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 22 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 23 | v1 "k8s.io/api/core/v1" 24 | "k8s.io/apimachinery/pkg/runtime" 25 | ) 26 | 27 | func (r receiverExt) hashringConfig() (runtime.Object, reconciler.DesiredState, error) { 28 | hashringConfig := make([]HashRingGroup, len(r.Spec.ReceiverGroups)) 29 | for i := range r.Spec.ReceiverGroups { 30 | receiverGroup := &r.Spec.ReceiverGroups[i] 31 | hashringConfig[i].HashRing = receiverGroup.Name 32 | hashringConfig[i].Tenants = receiverGroup.Tenants 33 | hashringConfig[i].Endpoints = r.generateEndpointsForGroup(receiverGroup) 34 | } 35 | hashringConfigJSON, err := json.Marshal(hashringConfig) 36 | if err != nil { 37 | return nil, nil, err 38 | } 39 | configmap := &v1.ConfigMap{ 40 | ObjectMeta: r.getMeta("hashring-config"), 41 | Data: map[string]string{ 42 | "hashring.json": string(hashringConfigJSON), 43 | }, 44 | } 45 | return configmap, reconciler.StatePresent, nil 46 | } 47 | 48 | func (r receiverExt) generateEndpointsForGroup(group *v1alpha1.ReceiverGroup) (endpoints []string) { 49 | replicas := int(group.Replicas) 50 | if replicas == 0 { 51 | replicas = 1 52 | } 53 | 54 | name := r.getName(group.Name) 55 | 56 | endpoints = make([]string, replicas) 57 | for i := range endpoints { 58 | endpoints[i] = fmt.Sprintf("%s-%d.%s:10907", name, i, name) 59 | } 60 | return 61 | } 62 | 63 | type HashRingGroup struct { 64 | HashRing string `json:"hashring,omitempty"` 65 | Endpoints []string `json:"endpoints,omitempty"` 66 | Tenants []string `json:"tenants,omitempty"` 67 | } 68 | 69 | //func (r *Receiver) GetEndpointsForTenant(tenantName string) []string{ 70 | // var endpoints []string 71 | // for _, receiverGroup := range r.ReceiverGroups { 72 | // if contains(receiverGroup.Tenants, tenantName) { 73 | // endpoints = append(endpoints, receiverGroup.Tenants...) 74 | // } 75 | // } 76 | // return endpoints 77 | //} 78 | // 79 | //// Check if a string contains an element 80 | //func contains(list []string, element string) bool { 81 | // for _, e := range list { 82 | // if e == element { 83 | // return true 84 | // } 85 | // } 86 | // return false 87 | //} 88 | -------------------------------------------------------------------------------- /pkg/resources/receiver/hashring_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package receiver 16 | 17 | import ( 18 | "encoding/json" 19 | "testing" 20 | 21 | "github.com/stretchr/testify/require" 22 | ) 23 | 24 | func TestHashRingGroupMarshal(t *testing.T) { 25 | input := []HashRingGroup{ 26 | { 27 | HashRing: "test", 28 | Endpoints: []string{"endpoint1", "endpoint2"}, 29 | Tenants: []string{"test"}, 30 | }, 31 | } 32 | expected := `[{"hashring":"test","endpoints":["endpoint1","endpoint2"],"tenants":["test"]}]` 33 | result, err := json.Marshal(input) 34 | require.NoError(t, err) 35 | require.Equal(t, expected, string(result)) 36 | } 37 | -------------------------------------------------------------------------------- /pkg/resources/receiver/receiver.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package receiver 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/utils" 19 | "github.com/banzaicloud/thanos-operator/pkg/resources" 20 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 21 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 | ) 23 | 24 | func extend(r *v1alpha1.Receiver) receiverExt { 25 | return receiverExt{ 26 | Receiver: r, 27 | } 28 | } 29 | 30 | type receiverExt struct { 31 | *v1alpha1.Receiver 32 | } 33 | 34 | func (r receiverExt) getLabels() resources.Labels { 35 | return resources.Labels{ 36 | resources.ManagedByLabel: r.Name, 37 | resources.NameLabel: v1alpha1.ReceiverName, 38 | } 39 | } 40 | 41 | func (r receiverExt) getMeta(suffix ...string) metav1.ObjectMeta { 42 | meta := r.GetObjectMeta(r.getName(suffix...)) 43 | return meta 44 | } 45 | 46 | func (r receiverExt) getMetaWithLabels() metav1.ObjectMeta { 47 | meta := r.getMeta() 48 | meta.Labels = r.getLabels() 49 | return meta 50 | } 51 | 52 | func (r receiverExt) getName(suffix ...string) string { 53 | return resources.QualifiedName(append([]string{r.Name, v1alpha1.ReceiverName}, suffix...)...) 54 | } 55 | 56 | func (r receiverExt) GetObjectMeta(name string) metav1.ObjectMeta { 57 | return metav1.ObjectMeta{ 58 | Name: name, 59 | Namespace: r.Namespace, 60 | OwnerReferences: []metav1.OwnerReference{ 61 | { 62 | APIVersion: r.APIVersion, 63 | Kind: r.Kind, 64 | Name: r.Name, 65 | UID: r.UID, 66 | Controller: utils.BoolPointer(true), 67 | }, 68 | }, 69 | } 70 | } 71 | 72 | //func (r receiverExt) GetServiceURLS() []string { 73 | // var urls []string 74 | // for _, endpoint := range r.StoreEndpoints { 75 | // urls = append(urls, (&receiverInstance{r, endpoint.DeepCopy()}).getSvc()) 76 | // } 77 | // return urls 78 | //} 79 | 80 | type receiverInstance struct { 81 | receiverExt 82 | receiverGroup *v1alpha1.ReceiverGroup 83 | } 84 | 85 | func (r *receiverInstance) getVolumeMeta(name string) metav1.ObjectMeta { 86 | meta := r.GetObjectMeta(name) 87 | meta.Labels = r.getLabels() 88 | return meta 89 | } 90 | 91 | func (r *receiverInstance) getMeta(suffix ...string) metav1.ObjectMeta { 92 | meta := r.receiverExt.getMeta(suffix...) 93 | meta.Labels = r.getLabels() 94 | return meta 95 | } 96 | 97 | func (r *receiverInstance) getLabels() resources.Labels { 98 | labels := r.receiverExt.getLabels() 99 | if r.receiverGroup != nil { 100 | labels["receiverGroup"] = r.receiverGroup.Name 101 | } 102 | return labels 103 | } 104 | 105 | func (r *receiverInstance) setArgs(args []string) []string { 106 | args = append(args, resources.GetArgs(r.receiverGroup)...) 107 | 108 | //Label 109 | 110 | // Local-endpoint 111 | 112 | return args 113 | } 114 | -------------------------------------------------------------------------------- /pkg/resources/receiver/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package receiver 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | corev1 "k8s.io/api/core/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/util/intstr" 25 | ) 26 | 27 | func (r receiverInstance) service() (runtime.Object, reconciler.DesiredState, error) { 28 | service := &corev1.Service{ 29 | ObjectMeta: r.receiverGroup.MetaOverrides.Merge(r.getMeta(r.receiverGroup.Name)), 30 | Spec: corev1.ServiceSpec{ 31 | Ports: []corev1.ServicePort{ 32 | { 33 | Name: "grpc", 34 | Protocol: corev1.ProtocolTCP, 35 | Port: int32(resources.GetPort(r.receiverGroup.GRPCAddress)), 36 | TargetPort: intstr.FromString("grpc"), 37 | }, 38 | { 39 | Name: "http", 40 | Protocol: corev1.ProtocolTCP, 41 | Port: int32(resources.GetPort(r.receiverGroup.HTTPAddress)), 42 | TargetPort: intstr.FromString("http"), 43 | }, 44 | { 45 | Name: "remote-write", 46 | Protocol: corev1.ProtocolTCP, 47 | Port: int32(resources.GetPort(r.receiverGroup.RemoteWriteAddress)), 48 | TargetPort: intstr.FromString("remote-write"), 49 | }, 50 | }, 51 | Selector: r.getLabels(), 52 | ClusterIP: corev1.ClusterIPNone, 53 | Type: corev1.ServiceTypeClusterIP, 54 | }, 55 | } 56 | if r.receiverGroup.ServiceOverrides != nil { 57 | if err := merge.Merge(service, r.receiverGroup.ServiceOverrides); err != nil { 58 | return service, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 59 | } 60 | } 61 | return service, reconciler.StatePresent, nil 62 | } 63 | 64 | func (r receiverExt) commonService() (runtime.Object, reconciler.DesiredState, error) { 65 | service := &corev1.Service{ 66 | ObjectMeta: r.getMetaWithLabels(), 67 | Spec: corev1.ServiceSpec{ 68 | Ports: []corev1.ServicePort{ 69 | { 70 | Name: "grpc", 71 | Protocol: corev1.ProtocolTCP, 72 | Port: 10907, 73 | TargetPort: intstr.FromString("grpc"), 74 | }, 75 | { 76 | Name: "http", 77 | Protocol: corev1.ProtocolTCP, 78 | Port: 10909, 79 | TargetPort: intstr.FromString("http"), 80 | }, 81 | { 82 | Name: "remote-write", 83 | Protocol: corev1.ProtocolTCP, 84 | Port: 10908, 85 | TargetPort: intstr.FromString("remote-write"), 86 | }, 87 | }, 88 | Selector: r.getLabels(), 89 | Type: corev1.ServiceTypeClusterIP, 90 | }, 91 | } 92 | return service, reconciler.StatePresent, nil 93 | } 94 | -------------------------------------------------------------------------------- /pkg/resources/receiver/servicemonitor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package receiver 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | prometheus "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" 20 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | ) 23 | 24 | func (r receiverInstance) serviceMonitor() (runtime.Object, reconciler.DesiredState, error) { 25 | serviceMonitor := &prometheus.ServiceMonitor{ 26 | ObjectMeta: r.receiverGroup.MetaOverrides.Merge(r.getMeta(r.receiverGroup.Name)), 27 | } 28 | desiredState := reconciler.StateAbsent 29 | if metrics := r.receiverGroup.Metrics; metrics != nil && metrics.ServiceMonitor { 30 | serviceMonitor.Spec = prometheus.ServiceMonitorSpec{ 31 | Endpoints: []prometheus.Endpoint{ 32 | { 33 | Port: "http", 34 | Path: metrics.Path, 35 | Interval: metrics.Interval, 36 | ScrapeTimeout: metrics.Timeout, 37 | }, 38 | }, 39 | Selector: v1.LabelSelector{ 40 | MatchLabels: r.getLabels(), 41 | }, 42 | SampleLimit: 0, 43 | } 44 | desiredState = reconciler.StatePresent 45 | } 46 | return serviceMonitor, desiredState, nil 47 | } 48 | -------------------------------------------------------------------------------- /pkg/resources/rule/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package rule 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | corev1 "k8s.io/api/core/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/util/intstr" 25 | ) 26 | 27 | func (r *ruleInstance) service() (runtime.Object, reconciler.DesiredState, error) { 28 | if r.Thanos.Spec.Rule != nil { 29 | rule := r.Thanos.Spec.Rule 30 | service := &corev1.Service{ 31 | ObjectMeta: rule.MetaOverrides.Merge(r.getMeta()), 32 | Spec: corev1.ServiceSpec{ 33 | Ports: []corev1.ServicePort{ 34 | { 35 | Name: "grpc", 36 | Protocol: corev1.ProtocolTCP, 37 | Port: resources.GetPort(rule.GRPCAddress), 38 | TargetPort: intstr.FromString("grpc"), 39 | }, 40 | { 41 | Name: "http", 42 | Protocol: corev1.ProtocolTCP, 43 | Port: resources.GetPort(rule.HttpAddress), 44 | TargetPort: intstr.FromString("http"), 45 | }, 46 | }, 47 | Selector: r.getLabels(), 48 | Type: corev1.ServiceTypeClusterIP, 49 | ClusterIP: corev1.ClusterIPNone, 50 | }, 51 | } 52 | if rule.ServiceOverrides != nil { 53 | err := merge.Merge(service, rule.ServiceOverrides) 54 | if err != nil { 55 | return service, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 56 | } 57 | } 58 | 59 | return service, reconciler.StatePresent, nil 60 | } 61 | delete := &corev1.Service{ 62 | ObjectMeta: r.getMeta(), 63 | } 64 | return delete, reconciler.StateAbsent, nil 65 | } 66 | -------------------------------------------------------------------------------- /pkg/resources/rule/servicemonitor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package rule 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | prometheus "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" 20 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | ) 23 | 24 | func (r *ruleInstance) serviceMonitor() (runtime.Object, reconciler.DesiredState, error) { 25 | if r.Thanos.Spec.Rule != nil && r.Thanos.Spec.Rule.Metrics.ServiceMonitor { 26 | metrics := r.Thanos.Spec.Rule.Metrics 27 | rule := r.Thanos.Spec.Rule.DeepCopy() 28 | meta := r.getMeta() 29 | serviceMonitor := &prometheus.ServiceMonitor{ 30 | ObjectMeta: rule.MetaOverrides.Merge(meta), 31 | Spec: prometheus.ServiceMonitorSpec{ 32 | Endpoints: []prometheus.Endpoint{ 33 | { 34 | Port: "http", 35 | Path: metrics.Path, 36 | Interval: metrics.Interval, 37 | ScrapeTimeout: metrics.Timeout, 38 | }, 39 | }, 40 | Selector: v1.LabelSelector{ 41 | MatchLabels: r.getLabels(), 42 | }, 43 | NamespaceSelector: prometheus.NamespaceSelector{ 44 | MatchNames: []string{ 45 | r.Thanos.Namespace, 46 | }, 47 | }, 48 | SampleLimit: 0, 49 | }, 50 | } 51 | return serviceMonitor, reconciler.StatePresent, nil 52 | } 53 | delete := &prometheus.ServiceMonitor{ 54 | ObjectMeta: r.getMeta(), 55 | } 56 | return delete, reconciler.StateAbsent, nil 57 | } 58 | -------------------------------------------------------------------------------- /pkg/resources/sidecar/ingress.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package sidecar 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | netv1 "k8s.io/api/networking/v1" 22 | "k8s.io/apimachinery/pkg/runtime" 23 | ) 24 | 25 | func (e *endpointService) ingressGRPC() (runtime.Object, reconciler.DesiredState, error) { 26 | if e.Spec.Ingress != nil { 27 | endpointIngress := e.Spec.Ingress 28 | pathType := netv1.PathTypeImplementationSpecific 29 | ingress := &netv1.Ingress{ 30 | ObjectMeta: e.getMeta(), 31 | Spec: netv1.IngressSpec{ 32 | Rules: []netv1.IngressRule{ 33 | { 34 | Host: endpointIngress.Host, 35 | IngressRuleValue: netv1.IngressRuleValue{ 36 | HTTP: &netv1.HTTPIngressRuleValue{ 37 | Paths: []netv1.HTTPIngressPath{ 38 | { 39 | Path: endpointIngress.Path, 40 | PathType: &pathType, 41 | Backend: netv1.IngressBackend{ 42 | Service: &netv1.IngressServiceBackend{ 43 | Name: e.GetName(), 44 | Port: netv1.ServiceBackendPort{ 45 | Name: "grpc", 46 | }, 47 | }, 48 | }, 49 | }, 50 | }, 51 | }, 52 | }, 53 | }, 54 | }, 55 | }, 56 | } 57 | if endpointIngress.Certificate != "" { 58 | ingress.Spec.TLS = []netv1.IngressTLS{ 59 | { 60 | Hosts: []string{endpointIngress.Host}, 61 | SecretName: endpointIngress.Certificate, 62 | }, 63 | } 64 | } 65 | if endpointIngress.IngressOverrides != nil { 66 | err := merge.Merge(ingress, endpointIngress.IngressOverrides) 67 | if err != nil { 68 | return ingress, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 69 | } 70 | } 71 | return ingress, reconciler.StatePresent, nil 72 | } 73 | delete := &netv1.Ingress{ 74 | ObjectMeta: e.getMeta(), 75 | } 76 | return delete, reconciler.StateAbsent, nil 77 | } 78 | -------------------------------------------------------------------------------- /pkg/resources/sidecar/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package sidecar 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 22 | corev1 "k8s.io/api/core/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/util/intstr" 25 | ) 26 | 27 | type endpointService struct { 28 | *v1alpha1.StoreEndpoint 29 | } 30 | 31 | func (e *endpointService) sidecarService() (runtime.Object, reconciler.DesiredState, error) { 32 | if e.Spec.Selector != nil { 33 | var grpcPort int32 = 10901 34 | var httpPort int32 = 10902 35 | labels := map[string]string{ 36 | "app": "prometheus", 37 | } 38 | if e.Spec.Selector.GRPCPort != 0 { 39 | grpcPort = e.Spec.Selector.GRPCPort 40 | } 41 | if e.Spec.Selector.HTTPPort != 0 { 42 | httpPort = e.Spec.Selector.HTTPPort 43 | } 44 | if e.Spec.Selector.Labels != nil { 45 | labels = e.Spec.Selector.Labels 46 | } 47 | service := &corev1.Service{ 48 | ObjectMeta: e.getMeta(), 49 | Spec: corev1.ServiceSpec{ 50 | Ports: []corev1.ServicePort{ 51 | { 52 | Name: "grpc", 53 | Protocol: corev1.ProtocolTCP, 54 | Port: grpcPort, 55 | TargetPort: intstr.FromString("grpc"), 56 | }, 57 | { 58 | Name: "http", 59 | Protocol: corev1.ProtocolTCP, 60 | Port: httpPort, 61 | TargetPort: intstr.FromString("http"), 62 | }, 63 | }, 64 | Selector: labels, 65 | Type: corev1.ServiceTypeClusterIP, 66 | ClusterIP: corev1.ClusterIPNone, 67 | }, 68 | } 69 | if e.Spec.ServiceOverrides != nil { 70 | err := merge.Merge(service, e.Spec.ServiceOverrides) 71 | if err != nil { 72 | return service, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 73 | } 74 | } 75 | 76 | return service, reconciler.StatePresent, nil 77 | } 78 | delete := &corev1.Service{ 79 | ObjectMeta: e.getMeta(), 80 | } 81 | return delete, reconciler.StateAbsent, nil 82 | } 83 | -------------------------------------------------------------------------------- /pkg/resources/sidecar/sidecar.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package sidecar 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/banzaicloud/operator-tools/pkg/utils" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 25 | ) 26 | 27 | func New(storeEndpoints *v1alpha1.StoreEndpointList, reconciler *resources.StoreEndpointComponentReconciler) *Sidecar { 28 | return &Sidecar{ 29 | StoreEndpoints: storeEndpoints.Items, 30 | StoreEndpointComponentReconciler: reconciler, 31 | } 32 | } 33 | 34 | type Sidecar struct { 35 | StoreEndpoints []v1alpha1.StoreEndpoint 36 | *resources.StoreEndpointComponentReconciler 37 | } 38 | 39 | func (e *endpointService) getName() string { 40 | return fmt.Sprintf("%s-%s", e.Name, v1alpha1.SidecarName) 41 | } 42 | 43 | func (e *endpointService) getMeta() metav1.ObjectMeta { 44 | meta := metav1.ObjectMeta{ 45 | Name: e.getName(), 46 | Namespace: e.Namespace, 47 | } 48 | meta.OwnerReferences = []metav1.OwnerReference{ 49 | { 50 | APIVersion: e.APIVersion, 51 | Kind: e.Kind, 52 | Name: e.Name, 53 | UID: e.UID, 54 | Controller: utils.BoolPointer(true), 55 | }, 56 | } 57 | meta.Labels = e.Labels 58 | meta.Annotations = e.Annotations 59 | return meta 60 | } 61 | 62 | func (s *Sidecar) serviceFactory() []resources.Resource { 63 | var serviceList []resources.Resource 64 | 65 | for _, endpoint := range s.StoreEndpoints { 66 | serviceList = append(serviceList, (&endpointService{endpoint.DeepCopy()}).sidecarService) 67 | serviceList = append(serviceList, (&endpointService{endpoint.DeepCopy()}).ingressGRPC) 68 | } 69 | 70 | return serviceList 71 | } 72 | 73 | func (s *Sidecar) Reconcile() (*reconcile.Result, error) { 74 | return s.ReconcileResources(s.serviceFactory()) 75 | } 76 | -------------------------------------------------------------------------------- /pkg/resources/store/ingress.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package store 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | netv1 "k8s.io/api/networking/v1" 22 | "k8s.io/apimachinery/pkg/runtime" 23 | ) 24 | 25 | func (e *storeInstance) ingressGRPC() (runtime.Object, reconciler.DesiredState, error) { 26 | if e.StoreEndpoint != nil && e.StoreEndpoint.Spec.Ingress != nil { 27 | endpointIngress := e.StoreEndpoint.Spec.Ingress 28 | pathType := netv1.PathTypeImplementationSpecific 29 | ingress := &netv1.Ingress{ 30 | ObjectMeta: e.StoreEndpoint.Spec.MetaOverrides.Merge(e.getMeta()), 31 | Spec: netv1.IngressSpec{ 32 | Rules: []netv1.IngressRule{ 33 | { 34 | Host: endpointIngress.Host, 35 | IngressRuleValue: netv1.IngressRuleValue{ 36 | HTTP: &netv1.HTTPIngressRuleValue{ 37 | Paths: []netv1.HTTPIngressPath{ 38 | { 39 | Path: endpointIngress.Path, 40 | PathType: &pathType, 41 | Backend: netv1.IngressBackend{ 42 | Service: &netv1.IngressServiceBackend{ 43 | Name: e.GetName(), 44 | Port: netv1.ServiceBackendPort{ 45 | Name: "grpc", 46 | }, 47 | }, 48 | }, 49 | }, 50 | }, 51 | }, 52 | }, 53 | }, 54 | }, 55 | }, 56 | } 57 | if endpointIngress.Certificate != "" { 58 | ingress.Spec.TLS = []netv1.IngressTLS{ 59 | { 60 | Hosts: []string{endpointIngress.Host}, 61 | SecretName: endpointIngress.Certificate, 62 | }, 63 | } 64 | } 65 | if endpointIngress.IngressOverrides != nil { 66 | err := merge.Merge(ingress, endpointIngress.IngressOverrides) 67 | if err != nil { 68 | return ingress, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 69 | } 70 | } 71 | return ingress, reconciler.StatePresent, nil 72 | } 73 | delete := &netv1.Ingress{ 74 | ObjectMeta: e.getMeta(), 75 | } 76 | return delete, reconciler.StateAbsent, nil 77 | } 78 | -------------------------------------------------------------------------------- /pkg/resources/store/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package store 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | corev1 "k8s.io/api/core/v1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | "k8s.io/apimachinery/pkg/util/intstr" 25 | ) 26 | 27 | func (s *storeInstance) service() (runtime.Object, reconciler.DesiredState, error) { 28 | if s.Thanos.Spec.StoreGateway != nil { 29 | store := s.Thanos.Spec.StoreGateway 30 | service := &corev1.Service{ 31 | ObjectMeta: s.StoreEndpoint.Spec.MetaOverrides.Merge(s.getMeta()), 32 | Spec: corev1.ServiceSpec{ 33 | Ports: []corev1.ServicePort{ 34 | { 35 | Name: "grpc", 36 | Protocol: corev1.ProtocolTCP, 37 | Port: resources.GetPort(store.GRPCAddress), 38 | TargetPort: intstr.FromString("grpc"), 39 | }, 40 | { 41 | Name: "http", 42 | Protocol: corev1.ProtocolTCP, 43 | Port: resources.GetPort(store.HttpAddress), 44 | TargetPort: intstr.FromString("http"), 45 | }, 46 | }, 47 | Selector: s.getLabels(), 48 | ClusterIP: corev1.ClusterIPNone, 49 | Type: corev1.ServiceTypeClusterIP, 50 | }, 51 | } 52 | if store.ServiceOverrides != nil { 53 | err := merge.Merge(service, store.ServiceOverrides) 54 | if err != nil { 55 | return service, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") 56 | } 57 | } 58 | return service, reconciler.StatePresent, nil 59 | } 60 | delete := &corev1.Service{ 61 | ObjectMeta: s.getMeta(), 62 | } 63 | return delete, reconciler.StateAbsent, nil 64 | } 65 | -------------------------------------------------------------------------------- /pkg/resources/store/servicemonitor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package store 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | prometheus "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" 20 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | ) 23 | 24 | func (s *storeInstance) serviceMonitor() (runtime.Object, reconciler.DesiredState, error) { 25 | if s.Thanos.Spec.StoreGateway != nil && s.Thanos.Spec.StoreGateway.Metrics.ServiceMonitor { 26 | metrics := s.Thanos.Spec.StoreGateway.Metrics 27 | meta := s.getMeta() 28 | serviceMonitor := &prometheus.ServiceMonitor{ 29 | ObjectMeta: s.StoreEndpoint.Spec.MetaOverrides.Merge(meta), 30 | Spec: prometheus.ServiceMonitorSpec{ 31 | Endpoints: []prometheus.Endpoint{ 32 | { 33 | Port: "http", 34 | Path: metrics.Path, 35 | Interval: metrics.Interval, 36 | ScrapeTimeout: metrics.Timeout, 37 | }, 38 | }, 39 | Selector: v1.LabelSelector{ 40 | MatchLabels: s.getLabels(), 41 | }, 42 | NamespaceSelector: prometheus.NamespaceSelector{ 43 | MatchNames: []string{ 44 | s.Thanos.Namespace, 45 | }, 46 | }, 47 | SampleLimit: 0, 48 | }, 49 | } 50 | return serviceMonitor, reconciler.StatePresent, nil 51 | } 52 | delete := &prometheus.ServiceMonitor{ 53 | ObjectMeta: s.getMeta(), 54 | } 55 | return delete, reconciler.StateAbsent, nil 56 | } 57 | -------------------------------------------------------------------------------- /pkg/resources/storeendpoint.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package resources 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 19 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 20 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 21 | ) 22 | 23 | type StoreEndpointComponentReconciler struct { 24 | StoreEndpoints []v1alpha1.StoreEndpoint 25 | *reconciler.GenericResourceReconciler 26 | } 27 | 28 | func (t *StoreEndpointComponentReconciler) ReconcileResources(resourceList []Resource) (*reconcile.Result, error) { 29 | return Dispatch(t.GenericResourceReconciler, resourceList) 30 | } 31 | 32 | func NewStoreEndpointComponentReconciler(storeEndpoints *v1alpha1.StoreEndpointList, genericReconciler *reconciler.GenericResourceReconciler) *StoreEndpointComponentReconciler { 33 | return &StoreEndpointComponentReconciler{ 34 | StoreEndpoints: storeEndpoints.Items, 35 | GenericResourceReconciler: genericReconciler, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pkg/resources/thanos.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package resources 16 | 17 | import ( 18 | "fmt" 19 | "strconv" 20 | "strings" 21 | 22 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 23 | "github.com/banzaicloud/operator-tools/pkg/utils" 24 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 25 | corev1 "k8s.io/api/core/v1" 26 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 | "k8s.io/apimachinery/pkg/util/intstr" 28 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 29 | ) 30 | 31 | func GetPort(address string) int32 { 32 | res := strings.Split(address, ":") 33 | if len(res) > 1 { 34 | port, err := strconv.Atoi(res[1]) 35 | if err != nil { 36 | return 0 37 | } 38 | return int32(port) 39 | } 40 | return 0 41 | } 42 | 43 | func GetProbe(port int32, path string) *corev1.Probe { 44 | return &corev1.Probe{ 45 | Handler: corev1.Handler{ 46 | HTTPGet: &corev1.HTTPGetAction{ 47 | Path: path, 48 | Port: intstr.FromInt(int(port)), 49 | }, 50 | }, 51 | InitialDelaySeconds: 5, 52 | TimeoutSeconds: 5, 53 | PeriodSeconds: 30, 54 | SuccessThreshold: 1, 55 | FailureThreshold: 2, 56 | } 57 | } 58 | 59 | type ThanosComponentReconciler struct { 60 | Thanos *v1alpha1.Thanos 61 | ThanosList []v1alpha1.Thanos 62 | StoreEndpoints []v1alpha1.StoreEndpoint 63 | *reconciler.GenericResourceReconciler 64 | } 65 | 66 | func (t *ThanosComponentReconciler) GetCommonLabels() Labels { 67 | return Labels{ 68 | ManagedByLabel: t.Thanos.Name, 69 | } 70 | } 71 | 72 | func (t *ThanosComponentReconciler) QualifiedName(name string) string { 73 | return fmt.Sprintf("%s-%s", t.Thanos.Name, name) 74 | } 75 | 76 | func (t *ThanosComponentReconciler) GetNameMeta(name string) metav1.ObjectMeta { 77 | return metav1.ObjectMeta{ 78 | Name: name, 79 | Namespace: t.Thanos.Namespace, 80 | } 81 | } 82 | 83 | func (t *ThanosComponentReconciler) GetObjectMeta(name string) metav1.ObjectMeta { 84 | meta := t.GetNameMeta(name) 85 | meta.OwnerReferences = []metav1.OwnerReference{ 86 | { 87 | APIVersion: t.Thanos.APIVersion, 88 | Kind: t.Thanos.Kind, 89 | Name: t.Thanos.Name, 90 | UID: t.Thanos.UID, 91 | Controller: utils.BoolPointer(true), 92 | }, 93 | } 94 | return meta 95 | } 96 | 97 | func (t *ThanosComponentReconciler) ReconcileResources(resourceList []Resource) (*reconcile.Result, error) { 98 | return Dispatch(t.GenericResourceReconciler, resourceList) 99 | } 100 | 101 | func NewThanosComponentReconciler(thanos *v1alpha1.Thanos, thanosList []v1alpha1.Thanos, storeEndpoints []v1alpha1.StoreEndpoint, genericReconciler *reconciler.GenericResourceReconciler) *ThanosComponentReconciler { 102 | return &ThanosComponentReconciler{ 103 | Thanos: thanos, 104 | ThanosList: thanosList, 105 | StoreEndpoints: storeEndpoints, 106 | GenericResourceReconciler: genericReconciler, 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /pkg/resources/thanosendpoint/query.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package thanosendpoint 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/operator-tools/pkg/typeoverride" 22 | "github.com/banzaicloud/operator-tools/pkg/utils" 23 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 24 | "k8s.io/apimachinery/pkg/runtime" 25 | ) 26 | 27 | func (r Reconciler) query() (runtime.Object, reconciler.DesiredState, error) { 28 | 29 | meta := r.endpoint.Spec.MetaOverrides.Merge(r.getDescendantMeta()) 30 | 31 | query := &v1alpha1.Thanos{ 32 | ObjectMeta: meta, 33 | Spec: v1alpha1.ThanosSpec{ 34 | Query: &v1alpha1.Query{ 35 | GRPCIngress: &v1alpha1.Ingress{ 36 | IngressOverrides: &typeoverride.IngressNetworkingV1beta1{ 37 | ObjectMeta: typeoverride.ObjectMeta{ 38 | Annotations: map[string]string{ 39 | "nginx.ingress.kubernetes.io/backend-protocol": "GRPC", 40 | "nginx.ingress.kubernetes.io/auth-tls-verify-client": "on", 41 | "nginx.ingress.kubernetes.io/auth-tls-secret": meta.Namespace + "/" + r.endpoint.Spec.CABundle, 42 | }, 43 | }, 44 | }, 45 | Certificate: r.endpoint.Spec.Certificate, 46 | Host: r.endpoint.Name, 47 | }, 48 | }, 49 | }, 50 | } 51 | 52 | if r.endpoint.Spec.IngressClassName != "" { 53 | query.Spec.Query.GRPCIngress.IngressOverrides.Spec.IngressClassName = utils.StringPointer(r.endpoint.Spec.IngressClassName) 54 | } 55 | 56 | if r.endpoint.Spec.QueryOverrides != nil { 57 | if err := merge.Merge(query.Spec.Query, r.endpoint.Spec.QueryOverrides); err != nil { 58 | return nil, nil, errors.WrapIf(err, "failed to merge overrides to base query resource") 59 | } 60 | } 61 | 62 | return query, reconciler.StatePresent, nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/resources/thanosendpoint/storeendpoint.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package thanosendpoint 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 22 | "k8s.io/apimachinery/pkg/runtime" 23 | ) 24 | 25 | func (r Reconciler) storeEndpoint() (runtime.Object, reconciler.DesiredState, error) { 26 | 27 | meta := r.endpoint.Spec.MetaOverrides.Merge(r.getDescendantMeta()) 28 | 29 | storeEndpoint := &v1alpha1.StoreEndpoint{ 30 | ObjectMeta: meta, 31 | Spec: v1alpha1.StoreEndpointSpec{ 32 | Selector: &v1alpha1.KubernetesSelector{}, 33 | Thanos: meta.Name, 34 | }, 35 | } 36 | 37 | if r.endpoint.Spec.StoreEndpointOverrides != nil { 38 | if err := merge.Merge(storeEndpoint.Spec, r.endpoint.Spec.StoreEndpointOverrides); err != nil { 39 | return nil, nil, errors.Wrap(err, "failed to merge storeendpoint overrides") 40 | } 41 | } 42 | 43 | return storeEndpoint, reconciler.StatePresent, nil 44 | } 45 | -------------------------------------------------------------------------------- /pkg/resources/thanospeer/query.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package thanospeer 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/merge" 20 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 21 | "github.com/banzaicloud/thanos-operator/pkg/resources" 22 | "github.com/banzaicloud/thanos-operator/pkg/sdk/api/v1alpha1" 23 | "k8s.io/apimachinery/pkg/runtime" 24 | ) 25 | 26 | func (r Reconciler) query(peerCert, peerCA string) resources.Resource { 27 | return func() (runtime.Object, reconciler.DesiredState, error) { 28 | meta := r.peer.Spec.MetaOverrides.Merge(r.getDescendantMeta()) 29 | 30 | serverName := r.peer.Name 31 | 32 | if r.peer.Spec.PeerEndpointAlias != "" { 33 | serverName = r.peer.Spec.PeerEndpointAlias 34 | } 35 | 36 | cert := r.peer.Spec.Certificate 37 | if cert == "" { 38 | cert = peerCert 39 | } 40 | ca := r.peer.Spec.CABundle 41 | if ca == "" { 42 | ca = peerCA 43 | } 44 | 45 | query := &v1alpha1.Thanos{ 46 | ObjectMeta: meta, 47 | Spec: v1alpha1.ThanosSpec{ 48 | Query: &v1alpha1.Query{ 49 | GRPCClientCertificate: cert, 50 | GRPCClientCA: ca, 51 | GRPCClientServerName: serverName, 52 | Stores: []string{ 53 | r.peer.Spec.EndpointAddress, 54 | }, 55 | }, 56 | }, 57 | } 58 | 59 | if r.peer.Spec.QueryOverrides != nil { 60 | if err := merge.Merge(query.Spec.Query, r.peer.Spec.QueryOverrides); err != nil { 61 | return nil, nil, errors.WrapIf(err, "failed to merge overrides to base query resource") 62 | } 63 | } 64 | 65 | return query, reconciler.StatePresent, nil 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pkg/resources/types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package resources 16 | 17 | import ( 18 | "emperror.dev/errors" 19 | "github.com/banzaicloud/operator-tools/pkg/reconciler" 20 | "k8s.io/apimachinery/pkg/runtime" 21 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 22 | ) 23 | 24 | const ( 25 | NameLabel = "app.kubernetes.io/name" 26 | InstanceLabel = "app.kubernetes.io/instance" 27 | VersionLabel = "app.kubernetes.io/version" 28 | ComponentLabel = "app.kubernetes.io/component" 29 | ManagedByLabel = "app.kubernetes.io/managed-by" 30 | ManagedByValue = "thanos-operator" 31 | StoreEndpoint = "monitoring.banzaicloud.io/storeendpoint" 32 | 33 | HealthCheckPath = "/-/healthy" 34 | ReadyCheckPath = "/-/ready" 35 | ) 36 | 37 | // ComponentReconciler reconciler interface 38 | type ComponentReconciler func() (*reconcile.Result, error) 39 | 40 | // Resource redeclaration of function with return type kubernetes Object 41 | type Resource func() (runtime.Object, reconciler.DesiredState, error) 42 | 43 | type Labels = map[string]string 44 | 45 | func Dispatch(rr reconciler.ResourceReconciler, resourceList []Resource) (*reconcile.Result, error) { 46 | for _, res := range resourceList { 47 | o, state, err := res() 48 | if err != nil { 49 | return nil, errors.WrapIf(err, "failed to create desired object") 50 | } 51 | if o == nil { 52 | return nil, errors.Errorf("Reconcile error! Resource %#v returns with nil object", res) 53 | } 54 | result, err := rr.ReconcileResource(o, state) 55 | if err != nil { 56 | return nil, errors.WrapIf(err, "failed to reconcile resource") 57 | } 58 | if result != nil { 59 | return result, nil 60 | } 61 | } 62 | return nil, nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/sdk/api/v1alpha1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | // Package v1alpha1 contains API Schema definitions for the monitoring v1alpha1 API group 16 | // +kubebuilder:object:generate=true 17 | // +groupName=monitoring.banzaicloud.io 18 | package v1alpha1 19 | 20 | import ( 21 | "k8s.io/apimachinery/pkg/runtime/schema" 22 | "sigs.k8s.io/controller-runtime/pkg/scheme" 23 | ) 24 | 25 | var ( 26 | // GroupVersion is group version used to register these objects 27 | GroupVersion = schema.GroupVersion{Group: "monitoring.banzaicloud.io", Version: "v1alpha1"} 28 | 29 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 30 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 31 | 32 | // AddToScheme adds the types in this group-version to the given scheme. 33 | AddToScheme = SchemeBuilder.AddToScheme 34 | ) 35 | -------------------------------------------------------------------------------- /pkg/sdk/api/v1alpha1/thanosendpoint_types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package v1alpha1 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/typeoverride" 19 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | ) 21 | 22 | // +kubebuilder:object:root=true 23 | // +kubebuilder:subresource:status 24 | // +kubebuilder:printcolumn:name="Endpoint Address",type="string",JSONPath=".status.endpointAddress" 25 | 26 | type ThanosEndpoint struct { 27 | metav1.TypeMeta `json:",inline"` 28 | metav1.ObjectMeta `json:"metadata,omitempty"` 29 | 30 | // See [ThanosEndpointSpec](#thanosendpointspec) 31 | Spec ThanosEndpointSpec `json:"spec,omitempty"` 32 | // See [ThanosEndpointStatus](#thanosendpointstatus) 33 | Status ThanosEndpointStatus `json:"status,omitempty"` 34 | } 35 | 36 | // +kubebuilder:object:root=true 37 | 38 | type ThanosEndpointList struct { 39 | metav1.TypeMeta `json:",inline"` 40 | metav1.ListMeta `json:"metadata,omitempty"` 41 | Items []ThanosEndpoint `json:"items"` 42 | } 43 | 44 | type ThanosEndpointSpec struct { 45 | // The endpoint should use this server certificate (tls.crt, tls.key) in the current namespace 46 | Certificate string `json:"certificate,omitempty"` 47 | 48 | // Reference the given ingressClass resource explicitly 49 | IngressClassName string `json:"ingressClassName,omitempty"` 50 | 51 | // Name of the secret that contains the CA certificate in ca.crt to verify client certs in the current namespace 52 | CABundle string `json:"caBundle,omitempty"` 53 | 54 | // List of statically configured store addresses 55 | Stores []string `json:"stores,omitempty"` 56 | 57 | // Custom replica labels if the default doesn't apply 58 | ReplicaLabels []string `json:"replicaLabels,omitempty"` 59 | 60 | // [Override metadata](../overrides/override/#objectmeta) for managed resources 61 | MetaOverrides typeoverride.ObjectMeta `json:"metaOverrides,omitempty"` 62 | 63 | // Override any of the [Query parameters](../thanos_types/#query) 64 | QueryOverrides *Query `json:"queryOverrides,omitempty"` 65 | 66 | // Override any of the [StoreEndpoint parameters](../storeendpoint_types/) 67 | StoreEndpointOverrides []StoreEndpointSpec `json:"storeEndpointOverrides,omitempty"` 68 | } 69 | 70 | type ThanosEndpointStatus struct { 71 | // Host (or IP) and port of the exposed Thanos endpoint 72 | EndpointAddress string `json:"endpointAddress,omitempty"` 73 | } 74 | 75 | func init() { 76 | SchemeBuilder.Register(&ThanosEndpoint{}, &ThanosEndpointList{}) 77 | } 78 | -------------------------------------------------------------------------------- /pkg/sdk/api/v1alpha1/thanospeer_types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package v1alpha1 16 | 17 | import ( 18 | "github.com/banzaicloud/operator-tools/pkg/typeoverride" 19 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | ) 21 | 22 | const ( 23 | PeerCertSecretLabel = "monitoring.banzaicloud.io/thanospeer" 24 | PeerCASecretLabel = "monitoring.banzaicloud.io/thanospeer-ca" 25 | ) 26 | 27 | // +kubebuilder:object:root=true 28 | // +kubebuilder:subresource:status 29 | // +kubebuilder:printcolumn:name="Endpoint Address",type="string",JSONPath=".spec.endpointAddress" 30 | // +kubebuilder:printcolumn:name="Alias",type="string",JSONPath=".spec.peerEndpointAlias" 31 | 32 | type ThanosPeer struct { 33 | metav1.TypeMeta `json:",inline"` 34 | metav1.ObjectMeta `json:"metadata,omitempty"` 35 | 36 | // See [ThanosPeerSpec](#thanospeerspec) 37 | Spec ThanosPeerSpec `json:"spec,omitempty"` 38 | // See [ThanosPeerStatus](#thanospeerstatus) 39 | Status ThanosPeerStatus `json:"status,omitempty"` 40 | } 41 | 42 | // +kubebuilder:object:root=true 43 | 44 | type ThanosPeerList struct { 45 | metav1.TypeMeta `json:",inline"` 46 | metav1.ListMeta `json:"metadata,omitempty"` 47 | Items []ThanosPeer `json:"items"` 48 | } 49 | 50 | type ThanosPeerSpec struct { 51 | // Host (or IP) and port of the remote Thanos endpoint 52 | EndpointAddress string `json:"endpointAddress"` 53 | 54 | // Optional alias for the remote endpoint in case we have to access it through a different name. 55 | // This is typically needed if the remote endpoint has a certificate created for a predefined hostname. 56 | // The controller should create an externalName service for this backed buy the actual peer endpoint host 57 | // or a k8s service with a manually crafted k8s endpoint if EndpointAddress doesn't have a host but only an IP. 58 | PeerEndpointAlias string `json:"peerEndpointAlias,omitempty"` 59 | 60 | // The peer query should use this client certificate (tls.crt, tls.key) in the current namespace 61 | Certificate string `json:"certificate,omitempty"` 62 | 63 | // Name of the secret that contains the CA certificate in ca.crt to verify client certs in the current namespace 64 | CABundle string `json:"caBundle,omitempty"` 65 | 66 | // Custom replica labels if the default doesn't apply 67 | ReplicaLabels []string `json:"replicaLabels,omitempty"` 68 | 69 | // [Override metadata](../overrides/override/#objectmeta) for managed resources 70 | MetaOverrides typeoverride.ObjectMeta `json:"metaOverrides,omitempty"` 71 | 72 | // Override any of the [Query parameters](../thanos_types/#query) 73 | QueryOverrides *Query `json:"queryOverrides,omitempty"` 74 | } 75 | 76 | type ThanosPeerStatus struct { 77 | // The peer query is available over HTTP on this internal service URL 78 | QueryHTTPServiceURL string `json:"queryHTTPServiceURL,omitempty"` 79 | } 80 | 81 | func init() { 82 | SchemeBuilder.Register(&ThanosPeer{}, &ThanosPeerList{}) 83 | } 84 | -------------------------------------------------------------------------------- /pkg/sdk/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/banzaicloud/thanos-operator/pkg/sdk 2 | 3 | go 1.17 4 | 5 | require ( 6 | emperror.dev/errors v0.8.0 7 | github.com/banzaicloud/operator-tools v0.26.0 8 | github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd 9 | k8s.io/api v0.22.2 10 | k8s.io/apiextensions-apiserver v0.22.2 11 | k8s.io/apimachinery v0.22.2 12 | sigs.k8s.io/controller-runtime v0.10.2 13 | ) 14 | 15 | require ( 16 | github.com/banzaicloud/k8s-objectmatcher v1.5.1 // indirect 17 | github.com/beorn7/perks v1.0.1 // indirect 18 | github.com/briandowns/spinner v1.12.0 // indirect 19 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 20 | github.com/cppforlife/go-patch v0.2.0 // indirect 21 | github.com/davecgh/go-spew v1.1.1 // indirect 22 | github.com/evanphx/json-patch v4.11.0+incompatible // indirect 23 | github.com/fatih/color v1.10.0 // indirect 24 | github.com/fsnotify/fsnotify v1.4.9 // indirect 25 | github.com/go-logr/logr v0.4.0 // indirect 26 | github.com/gogo/protobuf v1.3.2 // indirect 27 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 28 | github.com/golang/protobuf v1.5.2 // indirect 29 | github.com/google/go-cmp v0.5.5 // indirect 30 | github.com/google/gofuzz v1.1.0 // indirect 31 | github.com/google/uuid v1.1.2 // indirect 32 | github.com/googleapis/gnostic v0.5.5 // indirect 33 | github.com/iancoleman/orderedmap v0.2.0 // indirect 34 | github.com/imdario/mergo v0.3.12 // indirect 35 | github.com/json-iterator/go v1.1.11 // indirect 36 | github.com/mattn/go-colorable v0.1.8 // indirect 37 | github.com/mattn/go-isatty v0.0.12 // indirect 38 | github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect 39 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 40 | github.com/modern-go/reflect2 v1.0.1 // indirect 41 | github.com/pkg/errors v0.9.1 // indirect 42 | github.com/prometheus/client_golang v1.11.0 // indirect 43 | github.com/prometheus/client_model v0.2.0 // indirect 44 | github.com/prometheus/common v0.26.0 // indirect 45 | github.com/prometheus/procfs v0.6.0 // indirect 46 | github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect 47 | github.com/spf13/cast v1.3.1 // indirect 48 | github.com/spf13/pflag v1.0.5 // indirect 49 | github.com/wayneashleyberry/terminal-dimensions v1.0.0 // indirect 50 | go.uber.org/atomic v1.7.0 // indirect 51 | go.uber.org/multierr v1.6.0 // indirect 52 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect 53 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 54 | golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect 55 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 56 | golang.org/x/text v0.3.6 // indirect 57 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 58 | gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect 59 | google.golang.org/appengine v1.6.7 // indirect 60 | google.golang.org/protobuf v1.26.0 // indirect 61 | gopkg.in/inf.v0 v0.9.1 // indirect 62 | gopkg.in/yaml.v2 v2.4.0 // indirect 63 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 64 | k8s.io/client-go v0.22.2 // indirect 65 | k8s.io/component-base v0.22.2 // indirect 66 | k8s.io/klog/v2 v2.9.0 // indirect 67 | k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect 68 | k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect 69 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 70 | sigs.k8s.io/yaml v1.2.0 // indirect 71 | ) 72 | 73 | replace github.com/shurcooL/vfsgen => github.com/banzaicloud/vfsgen v0.0.0-20200203103248-c48ce8603af1 74 | -------------------------------------------------------------------------------- /pkg/sdk/resourcebuilder/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | // Copyright 2021 Banzai Cloud 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | // Code generated by controller-gen. DO NOT EDIT. 19 | 20 | package resourcebuilder 21 | 22 | import ( 23 | "github.com/banzaicloud/operator-tools/pkg/types" 24 | ) 25 | 26 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 27 | func (in *ComponentConfig) DeepCopyInto(out *ComponentConfig) { 28 | *out = *in 29 | in.EnabledComponent.DeepCopyInto(&out.EnabledComponent) 30 | if in.MetaOverrides != nil { 31 | in, out := &in.MetaOverrides, &out.MetaOverrides 32 | *out = new(types.MetaBase) 33 | (*in).DeepCopyInto(*out) 34 | } 35 | if in.WorkloadMetaOverrides != nil { 36 | in, out := &in.WorkloadMetaOverrides, &out.WorkloadMetaOverrides 37 | *out = new(types.MetaBase) 38 | (*in).DeepCopyInto(*out) 39 | } 40 | if in.WorkloadOverrides != nil { 41 | in, out := &in.WorkloadOverrides, &out.WorkloadOverrides 42 | *out = new(types.PodSpecBase) 43 | (*in).DeepCopyInto(*out) 44 | } 45 | if in.ContainerOverrides != nil { 46 | in, out := &in.ContainerOverrides, &out.ContainerOverrides 47 | *out = new(types.ContainerBase) 48 | (*in).DeepCopyInto(*out) 49 | } 50 | if in.DeploymentOverrides != nil { 51 | in, out := &in.DeploymentOverrides, &out.DeploymentOverrides 52 | *out = new(types.DeploymentSpecBase) 53 | (*in).DeepCopyInto(*out) 54 | } 55 | } 56 | 57 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentConfig. 58 | func (in *ComponentConfig) DeepCopy() *ComponentConfig { 59 | if in == nil { 60 | return nil 61 | } 62 | out := new(ComponentConfig) 63 | in.DeepCopyInto(out) 64 | return out 65 | } 66 | -------------------------------------------------------------------------------- /pkg/sdk/static/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Banzai Cloud 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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 | package main 16 | 17 | import ( 18 | "fmt" 19 | "net/http" 20 | "path" 21 | "path/filepath" 22 | "runtime" 23 | "time" 24 | 25 | "github.com/shurcooL/vfsgen" 26 | ) 27 | 28 | //go:generate go run main.go 29 | func main() { 30 | crds := http.Dir(filepath.Join(getRepoRoot(), "config/crd/bases")) 31 | 32 | err := vfsgen.Generate(crds, vfsgen.Options{ 33 | Filename: filepath.Join(getRepoRoot(), "pkg/sdk/static/gen/crds/generated.go"), 34 | PackageName: "crds", 35 | VariableName: "Root", 36 | FileModTime: timePointer(time.Time{}), 37 | }) 38 | if err != nil { 39 | panic(fmt.Sprintf("failed to generate crds vfs: %+v", err)) 40 | } 41 | 42 | rbac := http.Dir(filepath.Join(getRepoRoot(), "config/rbac")) 43 | 44 | err = vfsgen.Generate(rbac, vfsgen.Options{ 45 | Filename: filepath.Join(getRepoRoot(), "pkg/sdk/static/gen/rbac/generated.go"), 46 | PackageName: "rbac", 47 | VariableName: "Root", 48 | FileModTime: timePointer(time.Time{}), 49 | }) 50 | if err != nil { 51 | panic(fmt.Sprintf("failed to generate rbac vfs: %+v", err)) 52 | } 53 | } 54 | 55 | // getRepoRoot returns the full path to the root of the repo 56 | func getRepoRoot() string { 57 | _, filename, _, _ := runtime.Caller(0) 58 | 59 | dir := filepath.Dir(filename) 60 | 61 | return filepath.Dir(path.Join(dir, "../..")) 62 | } 63 | 64 | func timePointer(t time.Time) *time.Time { 65 | return &t 66 | } 67 | --------------------------------------------------------------------------------