From c8568eb8d56f7c39f4dc5bc14baefc44f17b50dc Mon Sep 17 00:00:00 2001 From: PINCHON Benjamin Date: Mon, 28 Oct 2024 16:50:11 +0100 Subject: [PATCH] feat(helm): init helm chart Signed-off-by: PINCHON Benjamin --- .github/ci/ct.yaml | 7 + .github/workflows/helm.yml | 93 +++++++ Makefile | 49 ++-- charts/powerdns-operator/.helmignore | 30 +++ charts/powerdns-operator/Chart.yaml | 36 +++ charts/powerdns-operator/README.md | 105 ++++++++ charts/powerdns-operator/README.md.gotmpl | 30 +++ charts/powerdns-operator/crds/README.md | 5 + .../crds/dns.cav.enablers.ob_rrsets.yaml | 115 ++++++++ .../crds/dns.cav.enablers.ob_zones.yaml | 115 ++++++++ charts/powerdns-operator/templates/NOTES.txt | 4 + .../powerdns-operator/templates/_helpers.tpl | 114 ++++++++ .../templates/deployment.yaml | 112 ++++++++ charts/powerdns-operator/templates/rbac.yaml | 209 +++++++++++++++ .../powerdns-operator/templates/secret.yaml | 18 ++ .../powerdns-operator/templates/service.yaml | 28 ++ .../templates/serviceaccount.yaml | 16 ++ .../templates/servicemonitor.yaml | 48 ++++ .../__snapshot__/controller_test.yaml.snap | 79 ++++++ .../metrics_service_test.yaml.snap | 23 ++ .../tests/__snapshot__/rbac_test.yaml.snap | 240 +++++++++++++++++ .../serviceaccount_test.yaml.snap | 13 + .../tests/controller_test.yaml | 247 ++++++++++++++++++ .../tests/metrics_service_test.yaml | 46 ++++ charts/powerdns-operator/tests/rbac_test.yaml | 15 ++ .../powerdns-operator/tests/secret_test.yaml | 26 ++ .../tests/serviceaccount_test.yaml | 24 ++ .../tests/servicemonitor_test.yaml | 34 +++ charts/powerdns-operator/values.yaml | 150 +++++++++++ 29 files changed, 2016 insertions(+), 15 deletions(-) create mode 100644 .github/ci/ct.yaml create mode 100644 .github/workflows/helm.yml create mode 100644 charts/powerdns-operator/.helmignore create mode 100644 charts/powerdns-operator/Chart.yaml create mode 100644 charts/powerdns-operator/README.md create mode 100644 charts/powerdns-operator/README.md.gotmpl create mode 100644 charts/powerdns-operator/crds/README.md create mode 100644 charts/powerdns-operator/crds/dns.cav.enablers.ob_rrsets.yaml create mode 100644 charts/powerdns-operator/crds/dns.cav.enablers.ob_zones.yaml create mode 100644 charts/powerdns-operator/templates/NOTES.txt create mode 100644 charts/powerdns-operator/templates/_helpers.tpl create mode 100644 charts/powerdns-operator/templates/deployment.yaml create mode 100644 charts/powerdns-operator/templates/rbac.yaml create mode 100644 charts/powerdns-operator/templates/secret.yaml create mode 100644 charts/powerdns-operator/templates/service.yaml create mode 100644 charts/powerdns-operator/templates/serviceaccount.yaml create mode 100644 charts/powerdns-operator/templates/servicemonitor.yaml create mode 100644 charts/powerdns-operator/tests/__snapshot__/controller_test.yaml.snap create mode 100644 charts/powerdns-operator/tests/__snapshot__/metrics_service_test.yaml.snap create mode 100644 charts/powerdns-operator/tests/__snapshot__/rbac_test.yaml.snap create mode 100644 charts/powerdns-operator/tests/__snapshot__/serviceaccount_test.yaml.snap create mode 100644 charts/powerdns-operator/tests/controller_test.yaml create mode 100644 charts/powerdns-operator/tests/metrics_service_test.yaml create mode 100644 charts/powerdns-operator/tests/rbac_test.yaml create mode 100644 charts/powerdns-operator/tests/secret_test.yaml create mode 100644 charts/powerdns-operator/tests/serviceaccount_test.yaml create mode 100644 charts/powerdns-operator/tests/servicemonitor_test.yaml create mode 100644 charts/powerdns-operator/values.yaml diff --git a/.github/ci/ct.yaml b/.github/ci/ct.yaml new file mode 100644 index 0000000..99542c0 --- /dev/null +++ b/.github/ci/ct.yaml @@ -0,0 +1,7 @@ +remote: origin +target-branch: main +validate-maintainers: false +check-version-increment: false +chart-dirs: + - charts +helm-extra-args: "--timeout=5m" \ No newline at end of file diff --git a/.github/workflows/helm.yml b/.github/workflows/helm.yml new file mode 100644 index 0000000..e906038 --- /dev/null +++ b/.github/workflows/helm.yml @@ -0,0 +1,93 @@ +name: Helm Chart + +on: + push: + branches: + - main + - release-* + paths: + - charts/powerdns-operator/Chart.yaml + + workflow_dispatch: {} + +permissions: + contents: read + +jobs: + lint-and-test: + name: Lint and Test + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Set up Helm + uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0 + + - name: Set up Python + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 + with: + python-version: 3.x + + - name: Set up Helm Chart Testing + uses: helm/chart-testing-action@e6669bcd63d7cb57cb4380c33043eebe5d111992 # v2.6.1 + + - name: Set up Artifact Hub + run: | + curl --fail --location https://github.com/artifacthub/hub/releases/download/v1.19.0/ah_1.19.0_linux_amd64.tar.gz --output /tmp/ah.tar.gz + echo "0e430493521ce387ca04d79b26646a86f92886dbcceb44985bb71082a9530ca5 /tmp/ah.tar.gz" | shasum --check + sudo tar --extract --file /tmp/ah.tar.gz --directory /usr/local/bin ah + + - name: Lint chart + run: | + ct lint --config .github/ci/.ct.yaml + ah lint --path charts/powerdns-operator + + - name: Install chart unittest + run: | + helm env + helm plugin install https://github.com/helm-unittest/helm-unittest + + - name: Run unitests + run: make helm-test + + release: + name: Release + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Set up Helm + uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0 + + - name: Run chart-releaser + uses: helm/chart-releaser-action@a917fd15b20e8b64b94d9158ad54cd6345335584 # v1.6.0 + if: | + github.ref == 'refs/heads/main' || + startsWith(github.ref, 'refs/heads/release-') + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + CR_RELEASE_NAME_TEMPLATE: helm-chart-{{ .Version }} + CR_SKIP_EXISTING: true + with: + charts_dir: charts diff --git a/Makefile b/Makefile index 5c25d3f..7d6c3ba 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,22 @@ # Image URL to use all building/pushing image targets IMG ?= controller:latest + +## Tool Versions +KUSTOMIZE_VERSION ?= v5.4.3 +CONTROLLER_TOOLS_VERSION ?= v0.16.2 +ENVTEST_VERSION ?= release-0.19 +GOLANGCI_LINT_VERSION ?= v1.61.0 + # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.31.0 +# Helm +HELM_UNITTEST_VERSION = 3.16.1-0.6.2 +HELM_DOCS_VERSION = v1.14.2 +HELM_DIR ?= charts/powerdns-operator + +OUTPUT_DIR ?= bin + # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) GOBIN=$(shell go env GOPATH)/bin @@ -67,7 +81,7 @@ help: ## Display this help. ##@ Conformance .PHONY: reviewable -reviewable: generate manifests lint ## Ensure a PR is ready for review. +reviewable: generate manifests helm-docs lint ## Ensure a PR is ready for review. @go mod tidy .PHONY: check-diff @@ -81,6 +95,7 @@ check-diff: reviewable ## Ensure branch is clean. .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=charts/powerdns-operator/crds .PHONY: generate generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. @@ -189,16 +204,26 @@ undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/. $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - -##@ Packaging -HELMIFY ?= $(LOCALBIN)/helmify +##@ Helm +helm-docs: + @cd $(HELM_DIR); \ + docker run --rm -v $(shell pwd)/$(HELM_DIR):/helm-docs -u $(shell id -u) jnorwood/helm-docs:$(HELM_DOCS_VERSION) -.PHONY: helmify -helmify: $(HELMIFY) ## Download helmify locally if necessary. -$(HELMIFY): $(LOCALBIN) - test -s $(LOCALBIN)/helmify || GOBIN=$(LOCALBIN) go install github.com/arttor/helmify/cmd/helmify@latest +HELM_VERSION ?= $(shell helm show chart $(HELM_DIR) | grep '^version:' | sed 's/version: //g') -helm: manifests kustomize helmify - $(KUSTOMIZE) build config/default | $(HELMIFY) -crd-dir -image-pull-secrets +helm-build: + @$(INFO) helm package + @helm package $(HELM_DIR) --dependency-update --destination $(OUTPUT_DIR)/chart + @mv $(OUTPUT_DIR)/chart/powerdns-operator-$(HELM_VERSION).tgz $(OUTPUT_DIR)/chart/powerdns-operator.tgz + @$(OK) helm package + +helm-test: + @cd $(HELM_DIR); \ + docker run --rm -ti -v $(shell pwd)/$(HELM_DIR):/apps -u $(shell id -u) helmunittest/helm-unittest:$(HELM_UNITTEST_VERSION) . + +helm-test-update: + @cd $(HELM_DIR); \ + docker run --rm -ti -v $(shell pwd)/$(HELM_DIR):/apps -u $(shell id -u) helmunittest/helm-unittest:$(HELM_UNITTEST_VERSION) -u . ##@ Dependencies @@ -214,12 +239,6 @@ CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION) ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION) GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION) -## Tool Versions -KUSTOMIZE_VERSION ?= v5.4.3 -CONTROLLER_TOOLS_VERSION ?= v0.16.2 -ENVTEST_VERSION ?= release-0.19 -GOLANGCI_LINT_VERSION ?= v1.61.0 - .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. $(KUSTOMIZE): $(LOCALBIN) diff --git a/charts/powerdns-operator/.helmignore b/charts/powerdns-operator/.helmignore new file mode 100644 index 0000000..1e3940a --- /dev/null +++ b/charts/powerdns-operator/.helmignore @@ -0,0 +1,30 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ + +# CRD Readme.md +templates/crds/README.md + +tests/ +README.md.gotmpl +.helmignore \ No newline at end of file diff --git a/charts/powerdns-operator/Chart.yaml b/charts/powerdns-operator/Chart.yaml new file mode 100644 index 0000000..9737b8f --- /dev/null +++ b/charts/powerdns-operator/Chart.yaml @@ -0,0 +1,36 @@ +apiVersion: v2 +name: powerdns-operator +description: Manage PowerDNS resources with Kubernetes +type: application +version: 0.1.0 +appVersion: 0.1.0 +kubeVersion: '>= 1.21.0-0' +keywords: + - powerdns-operator + - powerdns + - dns +home: https://orange-opensource.github.io/PowerDNS-Operator +icon: https://github.com/Orange-OpenSource/PowerDNS-Operator/blob/main/docs/assets/favicon.png?raw=true +maintainers: +- name: antrema +- name: mydoomfr +sources: + - https://github.com/Orange-OpenSource/PowerDNS-Operator +annotations: + artifacthub.io/crds: | + - kind: Zone + version: v1alpha1 + name: zone.dns.cav.enablers.ob + displayName: Zone + description: | + A Zone is a collection of records that are managed together. Zones can + be used to represent a domain, a subdomain, or a set of records that are + managed together. + - kind: RRset + version: v1alpha1 + name: rrset.dns.cav.enablers.ob + displayName: RRset + description: | + An RRset is a collection of records that share the same name and type. + RRsets can be used to represent a collection of records that are managed + together. \ No newline at end of file diff --git a/charts/powerdns-operator/README.md b/charts/powerdns-operator/README.md new file mode 100644 index 0000000..2ef6553 --- /dev/null +++ b/charts/powerdns-operator/README.md @@ -0,0 +1,105 @@ +# PowerDNS Operator + +[//]: # (README.md generated by gotmpl. DO NOT EDIT.) + +![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) + +Manage PowerDNS resources with Kubernetes + +## TL;DR +```bash +helm repo add orange-opensource https://orange-opensource.github.io/PowerDNS-Operator +helm install powerdns-operator orange-opensource/powerdns-operator +``` + +## Installing the Chart +To install the chart with the release name `powerdns-operator`: +```bash +helm install powerdns-operator orange-opensource/powerdns-operator +``` + +## Uninstalling the Chart +To uninstall the `powerdns-operator` deployment: +```bash +helm uninstall powerdns-operator +``` +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| annotations | object | `{}` | Annotations to add to the controller deployment. | +| commonLabels | object | `{}` | | +| credentials.data.PDNS_API_KEY | string | `"secret"` | Specifies the PowerDNS API key used to authenticate | +| credentials.data.PDNS_API_URL | string | `"http://powerdns.powerdns.svc:8081"` | Specifies the PowerDNS API URL PDNS_API_URL: "https://powerdns.example.local:8081" | +| credentials.data.PDNS_API_VHOST | string | `"localhost"` | Specifies the PowerDNS VHOST | +| credentials.existingSecret | string | `""` | Specifies whether to use an existing secret. | +| credentials.name | string | `""` | Specifies the secret name to create if `existingSecret` is empty. | +| dnsConfig | object | `{}` | Specifies `dnsOptions` to deployment | +| dnsPolicy | string | `"ClusterFirst"` | Specifies `dnsPolicy` to deployment | +| fullnameOverride | string | `""` | | +| global.affinity | object | `{}` | | +| global.compatibility.openshift.adaptSecurityContext | string | `"auto"` | Manages the securityContext properties to make them compatible with OpenShift. Possible values: auto - Apply configurations if it is detected that OpenShift is the target platform. force - Always apply configurations. disabled - No modification applied. | +| global.nodeSelector | object | `{}` | | +| global.tolerations | list | `[]` | | +| global.topologySpreadConstraints | list | `[]` | | +| hostNetwork | bool | `false` | Run the controller on the host network | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.repository | string | `"ghcr.io/orange-opensource/powerdns-operator"` | | +| image.tag | string | `""` | | +| imagePullSecrets | list | `[]` | Optional array of imagePullSecrets containing private registry credentials # Ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ | +| labels | object | `{}` | Extra Labels to add to the controller deployment. | +| livenessProbe.httpGet.path | string | `"/healthz"` | | +| livenessProbe.httpGet.port | int | `8081` | | +| livenessProbe.initialDelaySeconds | int | `15` | | +| livenessProbe.periodSeconds | int | `20` | | +| metrics.service.annotations | object | `{}` | | +| metrics.service.enabled | bool | `true` | | +| metrics.service.ipFamilies | list | `[]` | Sets the families that should be supported and the order in which they should be applied to ClusterIP as well. Can be IPv4 and/or IPv6. | +| metrics.service.ipFamilyPolicy | string | `""` | Set the ip family policy to configure dual-stack see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services) | +| metrics.service.port | int | `8080` | | +| metrics.serviceMonitor.additionalLabels | object | `{}` | | +| metrics.serviceMonitor.annotations | object | `{}` | | +| metrics.serviceMonitor.enabled | bool | `true` | | +| metrics.serviceMonitor.labels | object | `{}` | | +| metrics.serviceMonitor.metricRelabelings | list | `[]` | | +| metrics.serviceMonitor.namespace | string | `""` | | +| metrics.serviceMonitor.relabelings | list | `[]` | | +| metrics.serviceMonitor.scheme | string | `"http"` | | +| metrics.serviceMonitor.scrapeInterval | string | `"15s"` | | +| metrics.serviceMonitor.scrapeTimeout | string | `"10s"` | | +| metrics.serviceMonitor.tlsConfig | object | `{}` | | +| nameOverride | string | `""` | | +| namespaceOverride | string | `""` | | +| nodeSelector | object | `{}` | | +| podAnnotations | object | `{}` | Extra annotations to add to the pod. | +| podLabels | object | `{}` | Extra labels to add to the pod. | +| podSecurityContext.enabled | bool | `true` | | +| podSecurityContext.runAsNonRoot | bool | `true` | | +| priorityClassName | string | `""` | Pod priority class name. | +| rbac.create | bool | `true` | | +| readinessProbe.httpGet.path | string | `"/readyz"` | | +| readinessProbe.httpGet.port | int | `8081` | | +| readinessProbe.initialDelaySeconds | int | `5` | | +| readinessProbe.periodSeconds | int | `10` | | +| replicaCount | int | `1` | | +| resources.limits.cpu | string | `"500m"` | | +| resources.limits.memory | string | `"128Mi"` | | +| resources.requests.cpu | string | `"10m"` | | +| resources.requests.memory | string | `"64Mi"` | | +| securityContext.allowPrivilegeEscalation | bool | `false` | | +| securityContext.capabilities.drop[0] | string | `"ALL"` | | +| securityContext.enabled | bool | `true` | | +| securityContext.readOnlyRootFilesystem | bool | `true` | | +| securityContext.runAsNonRoot | bool | `true` | | +| securityContext.runAsUser | int | `1000` | | +| securityContext.seccompProfile.type | string | `"RuntimeDefault"` | | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account. | +| serviceAccount.create | bool | `true` | Specifies whether a service account should be created. | +| serviceAccount.extraLabels | object | `{}` | Extra Labels to add to the service account. | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | +| terminationGracePeriodSeconds | int | `10` | | +| tolerations | list | `[]` | | +| topologySpreadConstraints | list | `[]` | | \ No newline at end of file diff --git a/charts/powerdns-operator/README.md.gotmpl b/charts/powerdns-operator/README.md.gotmpl new file mode 100644 index 0000000..d695569 --- /dev/null +++ b/charts/powerdns-operator/README.md.gotmpl @@ -0,0 +1,30 @@ +{{- $chartRepo := "https://orange-opensource.github.io/PowerDNS-Operator" -}} +{{- $org := "orange-opensource" -}} +# PowerDNS Operator + +[//]: # (README.md generated by gotmpl. DO NOT EDIT.) + +{{ template "chart.typeBadge" . }}{{ template "chart.versionBadge" . }} + +{{ template "chart.description" . }} + +## TL;DR +```bash +helm repo add {{ $org }} {{ $chartRepo }} +helm install powerdns-operator {{ $org }}/{{ template "chart.name" . }} +``` + +## Installing the Chart +To install the chart with the release name `{{ template "chart.name" . }}`: +```bash +helm install {{ template "chart.name" . }} {{ $org }}/{{ template "chart.name" . }} +``` + +## Uninstalling the Chart +To uninstall the `{{ template "chart.name" . }}` deployment: +```bash +helm uninstall {{ template "chart.name" . }} +``` +The command removes all the Kubernetes components associated with the chart and deletes the release. + +{{ template "chart.valuesSection" . }} \ No newline at end of file diff --git a/charts/powerdns-operator/crds/README.md b/charts/powerdns-operator/crds/README.md new file mode 100644 index 0000000..53c7d81 --- /dev/null +++ b/charts/powerdns-operator/crds/README.md @@ -0,0 +1,5 @@ +# CRD Template Directory + +CRDs are autogenerated during helm packaging. To install the CRDs set `installCRDS: true` during helm install or upgrade. + +The latest CRDs in the repository are located [here](../../../../config/crd/bases). \ No newline at end of file diff --git a/charts/powerdns-operator/crds/dns.cav.enablers.ob_rrsets.yaml b/charts/powerdns-operator/crds/dns.cav.enablers.ob_rrsets.yaml new file mode 100644 index 0000000..7283216 --- /dev/null +++ b/charts/powerdns-operator/crds/dns.cav.enablers.ob_rrsets.yaml @@ -0,0 +1,115 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.2 + name: rrsets.dns.cav.enablers.ob +spec: + group: dns.cav.enablers.ob + names: + kind: RRset + listKind: RRsetList + plural: rrsets + singular: rrset + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.zoneRef.name + name: Zone + type: string + - jsonPath: .status.dnsEntryName + name: Name + type: string + - jsonPath: .spec.type + name: Type + type: string + - jsonPath: .spec.ttl + name: TTL + type: integer + - jsonPath: .status.syncStatus + name: Status + type: string + - jsonPath: .spec.records + name: Records + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: RRset is the Schema for the rrsets API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: RRsetSpec defines the desired state of RRset + properties: + comment: + description: Comment on RRSet. + type: string + name: + description: Name of the record + type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + records: + description: All records in this Resource Record Set. + items: + type: string + type: array + ttl: + description: DNS TTL of the records, in seconds. + format: int32 + type: integer + type: + description: Type of the record (e.g. "A", "PTR", "MX"). + type: string + zoneRef: + description: ZoneRef reference the zone the RRSet depends on. + properties: + name: + description: Name of the zone. + type: string + required: + - name + type: object + required: + - name + - records + - ttl + - type + - zoneRef + type: object + status: + description: RRsetStatus defines the observed state of RRset + properties: + dnsEntryName: + type: string + lastUpdateTime: + format: date-time + type: string + syncErrorDescription: + type: string + syncStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/powerdns-operator/crds/dns.cav.enablers.ob_zones.yaml b/charts/powerdns-operator/crds/dns.cav.enablers.ob_zones.yaml new file mode 100644 index 0000000..0aaf158 --- /dev/null +++ b/charts/powerdns-operator/crds/dns.cav.enablers.ob_zones.yaml @@ -0,0 +1,115 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.2 + name: zones.dns.cav.enablers.ob +spec: + group: dns.cav.enablers.ob + names: + kind: Zone + listKind: ZoneList + plural: zones + singular: zone + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.serial + name: Serial + type: integer + - jsonPath: .status.id + name: ID + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Zone is the Schema for the zones API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ZoneSpec defines the desired state of Zone + properties: + catalog: + description: The catalog this zone is a member of + type: string + kind: + description: Kind of the zone, one of "Native", "Master", "Slave", + "Producer", "Consumer". + enum: + - Native + - Master + - Slave + - Producer + - Consumer + type: string + nameservers: + description: List of the nameservers of the zone. + items: + pattern: ^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+$ + type: string + minItems: 1 + type: array + required: + - kind + - nameservers + type: object + status: + description: ZoneStatus defines the observed state of Zone + properties: + catalog: + description: The catalog this zone is a member of. + type: string + dnssec: + description: Whether or not this zone is DNSSEC signed. + type: boolean + edited_serial: + description: The SOA serial as seen in query responses. + format: int32 + type: integer + id: + description: ID define the opaque zone id. + type: string + kind: + description: Kind of the zone, one of "Native", "Master", "Slave", + "Producer", "Consumer". + type: string + masters: + description: List of IP addresses configured as a master for this + zone ("Slave" type zones only). + items: + type: string + type: array + name: + description: Name of the zone (e.g. "example.com.") + type: string + notified_serial: + description: The SOA serial notifications have been sent out for + format: int32 + type: integer + serial: + description: The SOA serial number. + format: int32 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/powerdns-operator/templates/NOTES.txt b/charts/powerdns-operator/templates/NOTES.txt new file mode 100644 index 0000000..38ead78 --- /dev/null +++ b/charts/powerdns-operator/templates/NOTES.txt @@ -0,0 +1,4 @@ +The powerdns operator has been deployed successfully in namespace {{ .Release.Namespace }}! + +More information on the different resources and how to configure them +can be found in our Github: {{ .Chart.Home }} \ No newline at end of file diff --git a/charts/powerdns-operator/templates/_helpers.tpl b/charts/powerdns-operator/templates/_helpers.tpl new file mode 100644 index 0000000..eda1384 --- /dev/null +++ b/charts/powerdns-operator/templates/_helpers.tpl @@ -0,0 +1,114 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "powerdns-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "powerdns-operator.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "powerdns-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "powerdns-operator.labels" -}} +helm.sh/chart: {{ include "powerdns-operator.chart" . }} +{{ include "powerdns-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.commonLabels}} +{{ toYaml .Values.commonLabels }} +{{- end }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "powerdns-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "powerdns-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "powerdns-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "powerdns-operator.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Determine the image to use +*/}} +{{- define "powerdns-operator.image" -}} +{{ printf "%s:v%s" .image.repository (.image.tag | default .chartAppVersion) }} +{{- end }} + +{{/* +Return true if the OpenShift is the detected platform +Usage: +{{- include "powerdns-operator.isOpenShift" . -}} +*/}} +{{- define "powerdns-operator.isOpenShift" -}} +{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1" -}} +{{- true -}} +{{- end -}} +{{- end -}} + +{{/* +Render the securityContext based on the provided securityContext + {{- include "powerdns-operator.renderSecurityContext" (dict "securityContext" .Values.securityContext "context" $) -}} +*/}} +{{- define "powerdns-operator.renderSecurityContext" -}} +{{- $adaptedContext := .securityContext -}} +{{- if .context.Values.global.compatibility -}} + {{- if .context.Values.global.compatibility.openshift -}} + {{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (include "powerdns-operator.isOpenShift" .context)) -}} + {{/* Remove OpenShift managed fields */}} + {{- $adaptedContext = omit $adaptedContext "fsGroup" "runAsUser" "runAsGroup" -}} + {{- if not .securityContext.seLinuxOptions -}} + {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{- omit $adaptedContext "enabled" | toYaml -}} +{{- end -}} + +{{/* +Create the name for the credentials secret. +*/}} +{{- define "powerdns-operator.credentials.name" -}} +{{- if .Values.credentials.existingSecret -}} + {{- .Values.credentials.existingSecret -}} +{{- else -}} + {{ default (include "powerdns-operator.fullname" .) .Values.credentials.name }} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/charts/powerdns-operator/templates/deployment.yaml b/charts/powerdns-operator/templates/deployment.yaml new file mode 100644 index 0000000..81d9b3a --- /dev/null +++ b/charts/powerdns-operator/templates/deployment.yaml @@ -0,0 +1,112 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "powerdns-operator.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: controller + {{- with .Values.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "powerdns-operator.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "powerdns-operator.labels" . | nindent 8 }} + app.kubernetes.io/component: controller + {{- with .Values.labels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.podLabels }} + {{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} + spec: + {{- if .Values.dnsConfig }} + dnsConfig: {{ toYaml .Values.dnsConfig | nindent 8 }} + {{- end }} + dnsPolicy: {{ .Values.dnsPolicy }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector | default .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity | default .Values.global.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations | default .Values.global.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints | default .Values.global.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- with .Values.podSecurityContext }} + {{- if and (.enabled) (gt (keys . | len) 1) }} + securityContext: + {{- include "powerdns-operator.renderSecurityContext" (dict "securityContext" . "context" $) | nindent 8 }} + {{- end }} + {{- end }} + serviceAccountName: {{ include "powerdns-operator.serviceAccountName" . }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + hostNetwork: {{ .Values.hostNetwork }} + containers: + - name: {{ .Chart.Name }} + args: + - --leader-elect + - --health-probe-bind-address=:8081 + - --metrics-bind-address=:{{ .Values.metrics.service.port }} + ports: + - containerPort: {{ .Values.metrics.service.port }} + protocol: TCP + name: http-metrics + command: + - /manager + {{- if or (.Values.credentials.existingSecret) (.Values.credentials.name) }} + envFrom: + {{- if .Values.credentials.existingSecret }} + - secretRef: + name: {{ .Values.credentials.existingSecret }} + {{- end }} + {{- if .Values.credentials.name }} + - secretRef: + name: {{ .Values.credentials.name }} + {{- end }} + {{- end }} + image: {{ include "powerdns-operator.image" (dict "chartAppVersion" .Chart.AppVersion "image" .Values.image) | trim }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.livenessProbe }} + livenessProbe: {{ toYaml .Values.livenessProbe | nindent 12 }} + {{- end }} + {{- if .Values.readinessProbe }} + readinessProbe: {{ toYaml .Values.readinessProbe | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.securityContext }} + {{- if and (.enabled) (gt (keys . | len) 1) }} + securityContext: + {{- include "powerdns-operator.renderSecurityContext" (dict "securityContext" . "context" $) | nindent 12 }} + {{- end }} + {{- end }} \ No newline at end of file diff --git a/charts/powerdns-operator/templates/rbac.yaml b/charts/powerdns-operator/templates/rbac.yaml new file mode 100644 index 0000000..1da4751 --- /dev/null +++ b/charts/powerdns-operator/templates/rbac.yaml @@ -0,0 +1,209 @@ +{{- if .Values.rbac.create -}} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "powerdns-operator.fullname" . }}-leader-election-role + namespace: {{ .Release.Namespace }} + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "powerdns-operator.fullname" . }}-manager-role + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets + - zones + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets/finalizers + - zones/finalizers + verbs: + - update +- apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets/status + - zones/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "powerdns-operator.fullname" . }}-rrset-editor-role + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "powerdns-operator.fullname" . }}-rrset-viewer-role + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets + verbs: + - get + - list + - watch +- apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "powerdns-operator.fullname" . }}-zone-editor-role + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - dns.cav.enablers.ob + resources: + - zones + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - dns.cav.enablers.ob + resources: + - zones/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "powerdns-operator.fullname" . }}-zone-viewer-role + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - dns.cav.enablers.ob + resources: + - zones + verbs: + - get + - list + - watch +- apiGroups: + - dns.cav.enablers.ob + resources: + - zones/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "powerdns-operator.fullname" . }}-leader-election-rolebinding + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "powerdns-operator.fullname" . }}-leader-election-role +subjects: + - kind: ServiceAccount + name: {{ include "powerdns-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "powerdns-operator.fullname" . }}-manager-rolebinding + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "powerdns-operator.fullname" . }}-manager-role +subjects: + - kind: ServiceAccount + name: {{ include "powerdns-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{ end }} \ No newline at end of file diff --git a/charts/powerdns-operator/templates/secret.yaml b/charts/powerdns-operator/templates/secret.yaml new file mode 100644 index 0000000..4be0b19 --- /dev/null +++ b/charts/powerdns-operator/templates/secret.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.credentials.name (not .Values.credentials.existingSecret) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "powerdns-operator.credentials.name" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} + {{- with .Values.metrics.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: Opaque +data: +{{- range $key, $value := .Values.credentials.data }} + {{ $key }}: {{ tpl $value $ | b64enc | quote }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/powerdns-operator/templates/service.yaml b/charts/powerdns-operator/templates/service.yaml new file mode 100644 index 0000000..721c455 --- /dev/null +++ b/charts/powerdns-operator/templates/service.yaml @@ -0,0 +1,28 @@ +{{- if .Values.metrics.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "powerdns-operator.fullname" . }}-metrics + namespace: {{ .Release.Namespace }} + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} + {{- with .Values.metrics.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: ClusterIP + {{- if .Values.metrics.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.metrics.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.metrics.service.ipFamilies }} + ipFamilies: {{ .Values.metrics.service.ipFamilies | toYaml | nindent 2 }} + {{- end }} + ports: + - name: http-metrics + port: {{ .Values.metrics.service.port }} + protocol: TCP + targetPort: http-metrics + selector: + {{- include "powerdns-operator.selectorLabels" . | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/charts/powerdns-operator/templates/serviceaccount.yaml b/charts/powerdns-operator/templates/serviceaccount.yaml new file mode 100644 index 0000000..0cbee7d --- /dev/null +++ b/charts/powerdns-operator/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "powerdns-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.extraLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/powerdns-operator/templates/servicemonitor.yaml b/charts/powerdns-operator/templates/servicemonitor.yaml new file mode 100644 index 0000000..064b199 --- /dev/null +++ b/charts/powerdns-operator/templates/servicemonitor.yaml @@ -0,0 +1,48 @@ +{{- if and ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) .Values.metrics.serviceMonitor.enabled -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "powerdns-operator.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "powerdns-operator.labels" . | nindent 4 }} + {{- with .Values.metrics.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "powerdns-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: http-metrics + interval: {{ .Values.metrics.serviceMonitor.scrapeInterval }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- if .Values.metrics.serviceMonitor.scheme }} + scheme: {{ .Values.metrics.serviceMonitor.scheme }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: {{- toYaml .Values.metrics.serviceMonitor.metricRelabelings | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.relabelings }} + relabelings: {{ toYaml .Values.metrics.serviceMonitor.relabelings | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.tlsConfig }} + tlsConfig: + {{- toYaml .Values.metrics.serviceMonitor.tlsConfig | nindent 6 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/powerdns-operator/tests/__snapshot__/controller_test.yaml.snap b/charts/powerdns-operator/tests/__snapshot__/controller_test.yaml.snap new file mode 100644 index 0000000..4f97e6a --- /dev/null +++ b/charts/powerdns-operator/tests/__snapshot__/controller_test.yaml.snap @@ -0,0 +1,79 @@ +should match snapshot of default values: + 1: | + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + app.kubernetes.io/component: controller + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator + namespace: NAMESPACE + spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: powerdns-operator + template: + metadata: + labels: + app.kubernetes.io/component: controller + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + spec: + containers: + - args: + - --leader-elect + - --health-probe-bind-address=:8081 + - --metrics-bind-address=:8080 + command: + - /manager + image: ghcr.io/orange-opensource/powerdns-operator:v0.1.0 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: powerdns-operator + ports: + - containerPort: 8080 + name: http-metrics + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + dnsPolicy: ClusterFirst + hostNetwork: false + securityContext: + runAsNonRoot: true + serviceAccountName: RELEASE-NAME-powerdns-operator + terminationGracePeriodSeconds: 10 diff --git a/charts/powerdns-operator/tests/__snapshot__/metrics_service_test.yaml.snap b/charts/powerdns-operator/tests/__snapshot__/metrics_service_test.yaml.snap new file mode 100644 index 0000000..fdea1a8 --- /dev/null +++ b/charts/powerdns-operator/tests/__snapshot__/metrics_service_test.yaml.snap @@ -0,0 +1,23 @@ +should match snapshot of default values: + 1: | + apiVersion: v1 + kind: Service + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator-metrics + namespace: NAMESPACE + spec: + ports: + - name: http-metrics + port: 8080 + protocol: TCP + targetPort: http-metrics + selector: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/name: powerdns-operator + type: ClusterIP diff --git a/charts/powerdns-operator/tests/__snapshot__/rbac_test.yaml.snap b/charts/powerdns-operator/tests/__snapshot__/rbac_test.yaml.snap new file mode 100644 index 0000000..7510b44 --- /dev/null +++ b/charts/powerdns-operator/tests/__snapshot__/rbac_test.yaml.snap @@ -0,0 +1,240 @@ +should match snapshot of default values: + 1: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator-leader-election-role + namespace: NAMESPACE + rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + 2: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator-manager-role + rules: + - apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets + - zones + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets/finalizers + - zones/finalizers + verbs: + - update + - apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets/status + - zones/status + verbs: + - get + - patch + - update + 3: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator-rrset-editor-role + rules: + - apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets/status + verbs: + - get + 4: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-view: "true" + name: RELEASE-NAME-powerdns-operator-rrset-viewer-role + rules: + - apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets + verbs: + - get + - list + - watch + - apiGroups: + - dns.cav.enablers.ob + resources: + - rrsets/status + verbs: + - get + 5: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator-zone-editor-role + rules: + - apiGroups: + - dns.cav.enablers.ob + resources: + - zones + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - dns.cav.enablers.ob + resources: + - zones/status + verbs: + - get + 6: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator-zone-viewer-role + rules: + - apiGroups: + - dns.cav.enablers.ob + resources: + - zones + verbs: + - get + - list + - watch + - apiGroups: + - dns.cav.enablers.ob + resources: + - zones/status + verbs: + - get + 7: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator-leader-election-rolebinding + namespace: NAMESPACE + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: RELEASE-NAME-powerdns-operator-leader-election-role + subjects: + - kind: ServiceAccount + name: RELEASE-NAME-powerdns-operator + namespace: NAMESPACE + 8: | + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator-manager-rolebinding + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: RELEASE-NAME-powerdns-operator-manager-role + subjects: + - kind: ServiceAccount + name: RELEASE-NAME-powerdns-operator + namespace: NAMESPACE diff --git a/charts/powerdns-operator/tests/__snapshot__/serviceaccount_test.yaml.snap b/charts/powerdns-operator/tests/__snapshot__/serviceaccount_test.yaml.snap new file mode 100644 index 0000000..33e2175 --- /dev/null +++ b/charts/powerdns-operator/tests/__snapshot__/serviceaccount_test.yaml.snap @@ -0,0 +1,13 @@ +should match snapshot of default values: + 1: | + apiVersion: v1 + kind: ServiceAccount + metadata: + labels: + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: powerdns-operator + app.kubernetes.io/version: 0.1.0 + helm.sh/chart: powerdns-operator-0.1.0 + name: RELEASE-NAME-powerdns-operator + namespace: NAMESPACE diff --git a/charts/powerdns-operator/tests/controller_test.yaml b/charts/powerdns-operator/tests/controller_test.yaml new file mode 100644 index 0000000..43c1ac8 --- /dev/null +++ b/charts/powerdns-operator/tests/controller_test.yaml @@ -0,0 +1,247 @@ +suite: test controller deployment +templates: + - deployment.yaml +tests: + - it: should match snapshot of default values + asserts: + - matchSnapshot: {} + - it: should set imagePullPolicy to Always + set: + image.pullPolicy: Always + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Always + - it: should imagePullPolicy to be default value IfNotPresent + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: IfNotPresent + - it: should override securityContext + set: + podSecurityContext: + runAsUser: 2000 + securityContext: + runAsUser: 3000 + asserts: + - equal: + path: spec.template.spec.securityContext + value: + runAsNonRoot: true + runAsUser: 2000 + - equal: + path: spec.template.spec.containers[0].securityContext + value: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 3000 + seccompProfile: + type: RuntimeDefault + - it: should override hostNetwork + set: + hostNetwork: true + asserts: + - equal: + path: spec.template.spec.hostNetwork + value: true + - it: should override metrics port + set: + metrics.service.port: 8888 + asserts: + - equal: + path: spec.template.spec.containers[0].args[2] + value: "--metrics-bind-address=:8888" + - it: should override image version + set: + image.repository: ghcr.io/orange-opensource/powerdns-operator + image.tag: 0.2.0 + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: ghcr.io/orange-opensource/powerdns-operator:v0.2.0 + - it: should override resources + set: + resources: + limits: + cpu: 1000m + memory: 256Mi + requests: + cpu: 20m + memory: 128Mi + asserts: + - equal: + path: spec.template.spec.containers[0].resources + value: + limits: + cpu: 1000m + memory: 256Mi + requests: + cpu: 20m + memory: 128Mi + - it: should override readinessProbe + set: + readinessProbe: + httpGet: + path: /fake-readyz + port: 8082 + initialDelaySeconds: 10 + periodSeconds: 15 + asserts: + - equal: + path: spec.template.spec.containers[0].readinessProbe + value: + httpGet: + path: /fake-readyz + port: 8082 + initialDelaySeconds: 10 + periodSeconds: 15 + - it: should override livenessProbe + set: + livenessProbe: + httpGet: + path: /fake-readyz + port: 8082 + initialDelaySeconds: 10 + periodSeconds: 15 + asserts: + - equal: + path: spec.template.spec.containers[0].livenessProbe + value: + httpGet: + path: /fake-readyz + port: 8082 + initialDelaySeconds: 10 + periodSeconds: 15 + - it: should override credentials (existing-secret) + set: + credentials: + existingSecret: "existing-secret" + asserts: + - equal: + path: spec.template.spec.containers[0].envFrom[0].secretRef.name + value: existing-secret + - it: should override credentials (new-secret) + set: + credentials: + existingSecret: "" + name: new-secret + data: + key1: value1 + asserts: + - equal: + path: spec.template.spec.containers[0].envFrom[0].secretRef.name + value: new-secret + - it: should override serviceAccountName + set: + serviceAccount: + name: new-service-account + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: new-service-account + - it: should override terminationGracePeriodSeconds + set: + terminationGracePeriodSeconds: 20 + asserts: + - equal: + path: spec.template.spec.terminationGracePeriodSeconds + value: 20 + - it: should override priorityClassName + set: + priorityClassName: high-priority + asserts: + - equal: + path: spec.template.spec.priorityClassName + value: high-priority + - it: should override topologySpreadConstraints + set: + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: powerdns-operator + asserts: + - equal: + path: spec.template.spec.topologySpreadConstraints + value: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: powerdns-operator + - it: should override tolerations + set: + tolerations: + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule + asserts: + - equal: + path: spec.template.spec.tolerations + value: + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule + - it: should override affinity + set: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/e2e-az-name + operator: In + values: + - e2e-az1 + - e2e-az2 + asserts: + - equal: + path: spec.template.spec.affinity + value: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/e2e-az-name + operator: In + values: + - e2e-az1 + - e2e-az2 + - it: should override nodeSelector + set: + nodeSelector: + disktype: ssd + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + disktype: ssd + - it: should override dnsPolicy + set: + dnsPolicy: ClusterFirstWithHostNet + asserts: + - equal: + path: spec.template.spec.dnsPolicy + value: ClusterFirstWithHostNet + - it: should override dnsConfig + set: + dnsConfig: + nameservers: + - 1.1.1.1 + - 8.8.8.8 + asserts: + - equal: + path: spec.template.spec.dnsConfig + value: + nameservers: + - 1.1.1.1 + - 8.8.8.8 diff --git a/charts/powerdns-operator/tests/metrics_service_test.yaml b/charts/powerdns-operator/tests/metrics_service_test.yaml new file mode 100644 index 0000000..d96697c --- /dev/null +++ b/charts/powerdns-operator/tests/metrics_service_test.yaml @@ -0,0 +1,46 @@ +suite: test metrics service +templates: + - service.yaml +tests: + - it: should match snapshot of default values + asserts: + - matchSnapshot: {} + - it: should render right if values given + set: + metrics: + service: + ipFamilyPolicy: DualStack + ipFamilies: + - IPv4 + - IPv6 + asserts: + - equal: + path: spec.ipFamilyPolicy + value: DualStack + - equal: + path: spec.ipFamilies + value: + - IPv4 + - IPv6 + - it: should contains right http-metrics port + set: + metrics: + service: + port: 4321 + asserts: + - contains: + path: spec.ports + content: + name: http-metrics + port: 4321 + protocol: TCP + targetPort: http-metrics + - equal: + path: spec.type + value: ClusterIP + - it: should contain document + asserts: + - containsDocument: + kind: Service + apiVersion: v1 + documentIndex: 0 \ No newline at end of file diff --git a/charts/powerdns-operator/tests/rbac_test.yaml b/charts/powerdns-operator/tests/rbac_test.yaml new file mode 100644 index 0000000..024aae7 --- /dev/null +++ b/charts/powerdns-operator/tests/rbac_test.yaml @@ -0,0 +1,15 @@ +suite: test rbac +templates: + - rbac.yaml +tests: + - it: should match snapshot of default values + asserts: + - matchSnapshot: {} + - it: Should contain both ClusterRole and ClusterRoleBinding documents + asserts: + - containsDocument: + kind: ClusterRoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + any: true + - hasDocuments: + count: 8 \ No newline at end of file diff --git a/charts/powerdns-operator/tests/secret_test.yaml b/charts/powerdns-operator/tests/secret_test.yaml new file mode 100644 index 0000000..074f299 --- /dev/null +++ b/charts/powerdns-operator/tests/secret_test.yaml @@ -0,0 +1,26 @@ +suite: test secret +templates: + - secret.yaml +tests: + - it: should create a secret with the defined credentials + set: + credentials: + name: override-super-secret + data: + password: somepassword + username: admin + documentIndex: 0 + asserts: + - containsDocument: + kind: Secret + apiVersion: v1 + - equal: + path: metadata.name + value: override-super-secret + - it: should not create a secret when credentials are not defined + set: + credentials: + name: "" + asserts: + - hasDocuments: + count: 0 diff --git a/charts/powerdns-operator/tests/serviceaccount_test.yaml b/charts/powerdns-operator/tests/serviceaccount_test.yaml new file mode 100644 index 0000000..e03cc46 --- /dev/null +++ b/charts/powerdns-operator/tests/serviceaccount_test.yaml @@ -0,0 +1,24 @@ +suite: test serviceaccount +templates: + - serviceaccount.yaml +tests: + - it: should match snapshot of default values + asserts: + - matchSnapshot: {} + - it: should ensure service account is created when enabled + set: + serviceAccount.create: true + asserts: + - isKind: + of: ServiceAccount + - equal: + path: metadata.name + value: RELEASE-NAME-powerdns-operator + - hasDocuments: + count: 1 + - it: should ensure service account is not created when disabled + set: + serviceAccount.create: false + asserts: + - hasDocuments: + count: 0 \ No newline at end of file diff --git a/charts/powerdns-operator/tests/servicemonitor_test.yaml b/charts/powerdns-operator/tests/servicemonitor_test.yaml new file mode 100644 index 0000000..bb2e450 --- /dev/null +++ b/charts/powerdns-operator/tests/servicemonitor_test.yaml @@ -0,0 +1,34 @@ +suite: test service monitor +templates: + - servicemonitor.yaml +tests: + - it: should render service monitor when APIVersions is present and serviceMonitor is enabled + set: + metrics.serviceMonitor.enabled: true + capabilities: + apiVersions: + - "monitoring.coreos.com/v1" + asserts: + - hasDocuments: + count: 1 + - it: should not render service monitor when APIVersions is not present but serviceMonitor is enabled + set: + metrics.serviceMonitor.enabled: true + asserts: + - hasDocuments: + count: 0 + - it: should not render service monitor when APIVersions is present and serviceMonitor is disabled + set: + metrics.serviceMonitor.enabled: false + capabilities: + apiVersions: + - "monitoring.coreos.com/v1" + asserts: + - hasDocuments: + count: 0 + - it: should not render service monitor when APIVersions is not present and serviceMonitor is disabled + set: + metrics.serviceMonitor.enabled: false + asserts: + - hasDocuments: + count: 0 \ No newline at end of file diff --git a/charts/powerdns-operator/values.yaml b/charts/powerdns-operator/values.yaml new file mode 100644 index 0000000..17c9286 --- /dev/null +++ b/charts/powerdns-operator/values.yaml @@ -0,0 +1,150 @@ +global: + nodeSelector: {} + tolerations: [] + topologySpreadConstraints: [] + affinity: {} + compatibility: + openshift: + # -- Manages the securityContext properties to make them compatible with OpenShift. + # Possible values: + # auto - Apply configurations if it is detected that OpenShift is the target platform. + # force - Always apply configurations. + # disabled - No modification applied. + adaptSecurityContext: auto + +replicaCount: 1 # we do not support more than 1 replica + +commonLabels: {} + +credentials: + # -- Specifies whether to use an existing secret. + existingSecret: "" + # -- Specifies the secret name to create if `existingSecret` is empty. + name: "" + data: + # -- Specifies the PowerDNS API URL + # PDNS_API_URL: "https://powerdns.example.local:8081" + PDNS_API_URL: "http://powerdns.powerdns.svc:8081" + # -- Specifies the PowerDNS API key used to authenticate + PDNS_API_KEY: "secret" + # -- Specifies the PowerDNS VHOST + PDNS_API_VHOST: "localhost" + +rbac: + create: true + +nodeSelector: {} +tolerations: [] +topologySpreadConstraints: [] +affinity: {} + +serviceAccount: + # -- Specifies whether a service account should be created. + create: true + # -- The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template. + name: "" + # -- Extra Labels to add to the service account. + extraLabels: {} + # -- Annotations to add to the service account. + annotations: {} + +image: + repository: "ghcr.io/orange-opensource/powerdns-operator" + pullPolicy: "IfNotPresent" + tag: "" + +# -- Extra Labels to add to the controller deployment. +labels: {} + +# -- Annotations to add to the controller deployment. +annotations: {} + +# -- Optional array of imagePullSecrets containing private registry credentials +## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: [] +# - name: secretName + +# -- Extra labels to add to the pod. +podLabels: {} + +# -- Extra annotations to add to the pod. +podAnnotations: {} + +# -- Specifies `dnsOptions` to deployment +dnsConfig: {} + +# -- Specifies `dnsPolicy` to deployment +dnsPolicy: ClusterFirst + +# -- Pod priority class name. +priorityClassName: "" + +terminationGracePeriodSeconds: 10 + +nameOverride: "" +fullnameOverride: "" +namespaceOverride: "" + +resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + +# -- Run the controller on the host network +hostNetwork: false + +podSecurityContext: + enabled: true + runAsNonRoot: true + +securityContext: + enabled: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + +livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + +readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + +metrics: + service: + enabled: true + annotations: {} + port: 8080 + # -- Set the ip family policy to configure dual-stack see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services) + ipFamilyPolicy: "" + # -- Sets the families that should be supported and the order in which they should be applied to ClusterIP as well. Can be IPv4 and/or IPv6. + ipFamilies: [] + serviceMonitor: + enabled: true + namespace: "" + labels: {} + annotations: {} + additionalLabels: {} + scrapeInterval: 15s + scrapeTimeout: 10s + scheme: http + metricRelabelings: [] + relabelings: [] + tlsConfig: {}