mirror of
https://github.com/prometheus-operator/prometheus-operator.git
synced 2025-04-21 19:49:46 +00:00
*: add v1beta1 for AlertmanagerConfig CRD (#4709)
* *: add v1beta1 for AlertmanagerConfig CRD Signed-off-by: Simon Pasquier <spasquie@redhat.com> * *: implement conversion webhook for AlertmanagerConfig Signed-off-by: Simon Pasquier <spasquie@redhat.com> * *: add jsonnet support for CRD conversion webhook Signed-off-by: Simon Pasquier <spasquie@redhat.com> * test: configure conversion webhook for AlertmanagerConfig Signed-off-by: Simon Pasquier <spasquie@redhat.com> * test/e2e: add test for v1alpha1<->v1beta1 conversion Signed-off-by: Simon Pasquier <spasquie@redhat.com> * Documentation: update webhook documentation Signed-off-by: Simon Pasquier <spasquie@redhat.com> * pkg/apis/monitoring/v1beta1: remove Regex field from Matcher type Signed-off-by: Simon Pasquier <spasquie@redhat.com> * *: rename muteTimeIntervals field to timeIntervals (v1beta1) Signed-off-by: Simon Pasquier <spasquie@redhat.com> * *: restore short name for AlertmanagerConfig Signed-off-by: Simon Pasquier <spasquie@redhat.com> * pkg/admission: add unit test for conversion webhook Signed-off-by: Simon Pasquier <spasquie@redhat.com> * pkg/apis/monitoring/v1beta1: replace v1.SecretKeySelector by SecretKeySelector v1.SecretKeySelector has an `Optional` field which doesn't make sense in the context of the AlertmanagerConfig CRD. Not depending on an external type also means that we can enforce that key and name values are not empty. Signed-off-by: Simon Pasquier <spasquie@redhat.com> * *: regenerate Signed-off-by: Simon Pasquier <spasquie@redhat.com> * *: make AlertmanagerConfig v1beta1 an opt-in choice Enabling by default AlertmanagerConfig v1beta1 by default means that users would have to configure the conversion webhook and it must be performed in advance or at the same time users upgrade to the latest operator version. To offer a smoother transition, we offer AlertmanagerConfig v1beta1 as an opt-in feature: it's neither included in the bundle.yaml file nor in the example/prometheus-operator-crd/ manifests. People that want to enable v1beta1 should use the example/prometheus-operator-crd-full manifests. For jsonnet users, the Prometheus operator jsonnet library has a new `enableAlertmanagerConfigV1beta1` configuration option that can be set to `true`. Signed-off-by: Simon Pasquier <spasquie@redhat.com> * *: add Telegram support in v1beta1 Signed-off-by: Simon Pasquier <spasquie@redhat.com> * *: synchronize with latest main changes Signed-off-by: Simon Pasquier <spasquie@redhat.com> * Documentation/user-guides/webhook.md: clarify mutation webhook Signed-off-by: Simon Pasquier <spasquie@redhat.com> * example: regenerate Signed-off-by: Simon Pasquier <spasquie@redhat.com>
This commit is contained in:
parent
b3e71e5e99
commit
1829e379cd
63 changed files with 42344 additions and 1071 deletions
Documentation/user-guides
Makefileexample
admission-webhook
alertmanager-crd-conversion
prometheus-operator-crd-full
monitoring.coreos.com_alertmanagerconfigs.yamlmonitoring.coreos.com_alertmanagers.yamlmonitoring.coreos.com_podmonitors.yamlmonitoring.coreos.com_probes.yamlmonitoring.coreos.com_prometheuses.yamlmonitoring.coreos.com_prometheusrules.yamlmonitoring.coreos.com_servicemonitors.yamlmonitoring.coreos.com_thanosrulers.yaml
jsonnet/prometheus-operator
admission-webhook.libsonnetalertmanagerconfigs-v1beta1-crd.libsonnetconversion.libsonnetprometheus-operator.libsonnet
pkg
admission
alertmanager
apis/monitoring
client
informers/externalversions
listers/monitoring/v1beta1
versioned
scripts/generate
build-conversion-webhook-patch-for-alermanagerconfig-crd.shconversion-webhook-patch-for-alermanagerconfig-crd.jsonnet
test
|
@ -1,50 +1,89 @@
|
|||
# Admission webhooks
|
||||
|
||||
This document describes how to set up an admission webhook to validate
|
||||
PrometheusRules, and thus preventing Prometheus from loading invalid
|
||||
configuration.
|
||||
This document describes how to deploy the Prometheus operator's admission webhook service.
|
||||
|
||||
The admission webhook can be used to:
|
||||
* Ensure that all annotations of PrometheusRule objects are coerced into string values.
|
||||
* Check that PrometheusRule objects are semantically valid.
|
||||
* Check that AlertmanagerConfig objects are semantically valid.
|
||||
* Convert AlertmanagerConfig objects between v1alpha1 and v1beta1 versions.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This guide assumes that you have already [deployed the Prometheus
|
||||
Operator](getting-started.md) and that [admission
|
||||
controllers are
|
||||
Operator](getting-started.md) and that [admission controllers are
|
||||
enabled](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#how-do-i-turn-on-an-admission-controller)
|
||||
on your cluster.
|
||||
|
||||
Admission webhooks require TLS, and as such this guide also assumes that you
|
||||
have a TLS certificate and key ready.
|
||||
The Kubernetes API server expects admission webhooks to communicate over HTTPS
|
||||
so this guide also assumes the following:
|
||||
1. A valid TLS certificate and key has been provisioned for the admission webhook service.
|
||||
2. A secret holding the TLS certificate and key has been created.
|
||||
|
||||
## Preparing the Operator
|
||||
If you don't want to manually provision the TLS materials,
|
||||
[cert-manager](https://cert-manager.io/) is a good option.
|
||||
|
||||
A secret needs to be created from the TLS certificate and key, assuming the
|
||||
certificate is in `tls.crt` and the key in `tls.key`:
|
||||
## Admission webhook deployment
|
||||
|
||||
```bash
|
||||
kubectl create secret tls prometheus-operator-certs --cert=tls.crt --key=tls.key
|
||||
Assuming that the following secret exists and contains the base64-encoded
|
||||
[PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) certificate
|
||||
(`tls.crt`) and key (`tls.key`) for the admission webhook service.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
data:
|
||||
tls.crt: LS0tLS...LS0tCg==
|
||||
tls.key: LS0tLS...LS0tCg==
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: admission-webhook-certs
|
||||
namespace: default
|
||||
```
|
||||
|
||||
The Prometheus Operator will serve the admission webhook. However, to do so, it
|
||||
requires being available over TLS, and not only plain HTTP. Thus the following
|
||||
flags need to be added to the Prometheus Operator deployment:
|
||||
The admission webhook's pod template should be modified to mount the secret as a
|
||||
volume and the container arguments should be modified to include the
|
||||
certificate and key:
|
||||
|
||||
* `--web.enable-tls=true` to enable the Prometheus Operator to serve its API
|
||||
over TLS,
|
||||
|
||||
* `--web.cert-file` to load the TLS certificate to use,
|
||||
|
||||
* `--web.key-file` to load the associate key.
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: prometheus-operator-admission-webhook
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: prometheus-operator-admission-webhook
|
||||
args:
|
||||
- --web.enable-tls=true
|
||||
- --web.cert-file=/etc/tls/private/tls.crt
|
||||
- --web.key-file=/etc/tls/private/tls.key
|
||||
volumeMounts:
|
||||
- mountPath: /etc/tls/private
|
||||
name: tls-certificates
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: tls-certificates
|
||||
- secret:
|
||||
secretName: admission-webhook-certs
|
||||
```
|
||||
|
||||
## Webhook endpoints
|
||||
|
||||
### caBundle note
|
||||
|
||||
The `caBundle` contains the base64-encoded CA certificate used to sign the
|
||||
webhook's certificate.
|
||||
The `caBundle` field contains the base64-encoded CA certificate used to sign the
|
||||
webhook's certificate. It is used by the Kubernetes API server to validate the
|
||||
certificate of the webhook service.
|
||||
|
||||
Certificate managers like [cert-manager](https://cert-manager.io/) supports CA
|
||||
injection into webhook configurations and custom resource definitions.
|
||||
|
||||
### `/admission-prometheusrules/validate`
|
||||
|
||||
The endpoint `/admission-prometheusrules/validate` rejects rules that are not valid prometheus config.
|
||||
The endpoint `/admission-prometheusrules/validate` rejects `PrometheusRule`
|
||||
objects that are not valid.
|
||||
|
||||
The following example deploys the validating admission webhook:
|
||||
|
||||
|
@ -55,7 +94,7 @@ metadata:
|
|||
name: prometheus-operator-rulesvalidation
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: SOMECABASE64ENCODED==
|
||||
caBundle: LS0tLS...LS0tCg==
|
||||
service:
|
||||
name: prometheus-operator
|
||||
namespace: default
|
||||
|
@ -79,7 +118,9 @@ webhooks:
|
|||
|
||||
### `/admission-prometheusrules/mutate`
|
||||
|
||||
The endpoint `/admission-prometheusrules/mutate` ensures that integers and boolean yaml data elements are cooerced into strings.
|
||||
The endpoint `/admission-prometheusrules/mutate` mutates `PrometheusRule`
|
||||
objects so that integers and boolean yaml data elements are coerced into
|
||||
strings.
|
||||
|
||||
The following example deploys the mutating admission webhook:
|
||||
|
||||
|
@ -90,7 +131,7 @@ metadata:
|
|||
name: prometheus-operator-rulesmutation
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: SOMECABASE64ENCODED==
|
||||
caBundle: LS0tLS...LS0tCg==
|
||||
service:
|
||||
name: prometheus-operator
|
||||
namespace: default
|
||||
|
@ -114,7 +155,8 @@ webhooks:
|
|||
|
||||
### `/admission-alertmanagerconfigs/validate`
|
||||
|
||||
The endpoint `/admission-alertmanagerconfigs/validate` rejects alertmanagerconfigs that are not valid alertmanager config.
|
||||
The endpoint `/admission-alertmanagerconfigs/validate` rejects
|
||||
`AlertmanagerConfig` objects that are not valid.
|
||||
|
||||
The following example deploys the validating admission webhook:
|
||||
|
||||
|
@ -125,7 +167,7 @@ metadata:
|
|||
name: prometheus-operator-alertmanager-config-validation
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: SOMECABASE64ENCODED==
|
||||
caBundle: LS0tLS...LS0tCg==
|
||||
service:
|
||||
name: prometheus-operator
|
||||
namespace: default
|
||||
|
@ -146,3 +188,42 @@ webhooks:
|
|||
admissionReviewVersions: ["v1", "v1beta1"]
|
||||
sideEffects: None
|
||||
```
|
||||
|
||||
### `/convert`
|
||||
|
||||
The endpoint `/convert` convert `Alertmanagerconfig` objects between `v1alpha1`
|
||||
and `v1beta1` versions.
|
||||
|
||||
The following example is a patch for the
|
||||
`alertmanagerconfigs.monitoring.coreos.com` CRD to configure the conversion
|
||||
webhook.
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "apiextensions.k8s.io/v1",
|
||||
"kind": "CustomResourceDefinition",
|
||||
"metadata": {
|
||||
"name": "alertmanagerconfigs.monitoring.coreos.com"
|
||||
},
|
||||
"spec": {
|
||||
"conversion": {
|
||||
"strategy": "Webhook",
|
||||
"webhook": {
|
||||
"clientConfig": {
|
||||
"service": {
|
||||
"name": "prometheus-operator-admission-webhook",
|
||||
"namespace": "default",
|
||||
"path": "/convert",
|
||||
"port": 8443
|
||||
},
|
||||
"caBundle": "LS0tLS...LS0tCg=="
|
||||
},
|
||||
"conversionReviewVersions": [
|
||||
"v1beta1",
|
||||
"v1alpha1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
36
Makefile
36
Makefile
|
@ -19,6 +19,7 @@ TYPES_V1_TARGET := pkg/apis/monitoring/v1/types.go
|
|||
TYPES_V1_TARGET += pkg/apis/monitoring/v1/thanos_types.go
|
||||
|
||||
TYPES_V1ALPHA1_TARGET := pkg/apis/monitoring/v1alpha1/alertmanager_config_types.go
|
||||
TYPES_V1BETA1_TARGET := pkg/apis/monitoring/v1beta1/alertmanager_config_types.go
|
||||
|
||||
TOOLS_BIN_DIR ?= $(shell pwd)/tmp/bin
|
||||
export PATH := $(TOOLS_BIN_DIR):$(PATH)
|
||||
|
@ -42,6 +43,7 @@ K8S_GEN_ARGS:=--go-header-file $(shell pwd)/.header --v=1 --logtostderr
|
|||
K8S_GEN_DEPS:=.header
|
||||
K8S_GEN_DEPS+=$(TYPES_V1_TARGET)
|
||||
K8S_GEN_DEPS+=$(TYPES_V1ALPHA1_TARGET)
|
||||
K8S_GEN_DEPS+=$(TYPES_V1BETA1_TARGET)
|
||||
K8S_GEN_DEPS+=$(foreach bin,$(K8S_GEN_BINARIES),$(TOOLS_BIN_DIR)/$(bin))
|
||||
|
||||
BUILD_DATE=$(shell date +"%Y%m%d-%T")
|
||||
|
@ -109,12 +111,14 @@ admission-webhook:
|
|||
po-lint:
|
||||
$(GO_BUILD_RECIPE) -o po-lint cmd/po-lint/main.go
|
||||
|
||||
DEEPCOPY_TARGETS := pkg/apis/monitoring/v1/zz_generated.deepcopy.go pkg/apis/monitoring/v1alpha1/zz_generated.deepcopy.go
|
||||
DEEPCOPY_TARGETS := pkg/apis/monitoring/v1/zz_generated.deepcopy.go pkg/apis/monitoring/v1alpha1/zz_generated.deepcopy.go pkg/apis/monitoring/v1beta1/zz_generated.deepcopy.go
|
||||
$(DEEPCOPY_TARGETS): $(CONTROLLER_GEN_BINARY)
|
||||
cd ./pkg/apis/monitoring/v1 && $(CONTROLLER_GEN_BINARY) object:headerFile=$(CURDIR)/.header \
|
||||
paths=.
|
||||
cd ./pkg/apis/monitoring/v1alpha1 && $(CONTROLLER_GEN_BINARY) object:headerFile=$(CURDIR)/.header \
|
||||
paths=.
|
||||
cd ./pkg/apis/monitoring/v1beta1 && $(CONTROLLER_GEN_BINARY) object:headerFile=$(CURDIR)/.header \
|
||||
paths=.
|
||||
|
||||
CLIENT_TARGET := pkg/client/versioned/clientset.go
|
||||
$(CLIENT_TARGET): $(K8S_GEN_DEPS)
|
||||
|
@ -122,23 +126,23 @@ $(CLIENT_TARGET): $(K8S_GEN_DEPS)
|
|||
$(K8S_GEN_ARGS) \
|
||||
--input-base "" \
|
||||
--clientset-name "versioned" \
|
||||
--input "$(GO_PKG)/pkg/apis/monitoring/v1,$(GO_PKG)/pkg/apis/monitoring/v1alpha1" \
|
||||
--input "$(GO_PKG)/pkg/apis/monitoring/v1,$(GO_PKG)/pkg/apis/monitoring/v1alpha1,$(GO_PKG)/pkg/apis/monitoring/v1beta1" \
|
||||
--output-package "$(GO_PKG)/pkg/client"
|
||||
|
||||
LISTER_TARGETS := pkg/client/listers/monitoring/v1/prometheus.go pkg/client/listers/monitoring/v1alpha1/prometheus.go
|
||||
LISTER_TARGETS := pkg/client/listers/monitoring/v1/interface.go pkg/client/listers/monitoring/v1alpha1/interface.go pkg/client/listers/monitoring/v1beta1/interface.go
|
||||
$(LISTER_TARGETS): $(K8S_GEN_DEPS)
|
||||
$(LISTER_GEN_BINARY) \
|
||||
$(K8S_GEN_ARGS) \
|
||||
--input-dirs "$(GO_PKG)/pkg/apis/monitoring/v1,$(GO_PKG)/pkg/apis/monitoring/v1alpha1" \
|
||||
--input-dirs "$(GO_PKG)/pkg/apis/monitoring/v1,$(GO_PKG)/pkg/apis/monitoring/v1alpha1,$(GO_PKG)/pkg/apis/monitoring/v1beta1" \
|
||||
--output-package "$(GO_PKG)/pkg/client/listers"
|
||||
|
||||
INFORMER_TARGETS := pkg/client/informers/externalversions/monitoring/v1/prometheus.go pkg/client/informers/externalversions/monitoring/v1alpha1/prometheus.go
|
||||
INFORMER_TARGETS := pkg/client/informers/externalversions/monitoring/v1/interface.go pkg/client/informers/externalversions/monitoring/v1alpha1/interface.go pkg/client/informers/externalversions/monitoring/v1beta1/interface.go
|
||||
$(INFORMER_TARGETS): $(K8S_GEN_DEPS) $(LISTER_TARGETS) $(CLIENT_TARGET)
|
||||
$(INFORMER_GEN_BINARY) \
|
||||
$(K8S_GEN_ARGS) \
|
||||
--versioned-clientset-package "$(GO_PKG)/pkg/client/versioned" \
|
||||
--listers-package "$(GO_PKG)/pkg/client/listers" \
|
||||
--input-dirs "$(GO_PKG)/pkg/apis/monitoring/v1,$(GO_PKG)/pkg/apis/monitoring/v1alpha1" \
|
||||
--input-dirs "$(GO_PKG)/pkg/apis/monitoring/v1,$(GO_PKG)/pkg/apis/monitoring/v1alpha1,$(GO_PKG)/pkg/apis/monitoring/v1beta1" \
|
||||
--output-package "$(GO_PKG)/pkg/client/informers"
|
||||
|
||||
.PHONY: k8s-gen
|
||||
|
@ -195,13 +199,19 @@ tidy:
|
|||
cd scripts && go mod tidy -v -modfile=go.mod
|
||||
|
||||
.PHONY: generate
|
||||
generate: $(DEEPCOPY_TARGETS) generate-crds bundle.yaml example/mixin/alerts.yaml example/thanos/thanos.yaml example/admission-webhook generate-docs
|
||||
generate: $(DEEPCOPY_TARGETS) generate-crds bundle.yaml example/mixin/alerts.yaml example/thanos/thanos.yaml example/admission-webhook example/alertmanager-crd-conversion generate-docs
|
||||
|
||||
# For now, the v1beta1 CRDs aren't part of the default bundle because they
|
||||
# require to deploy/run the conversion webhook.
|
||||
# They are provided in a separate directory
|
||||
# (example/prometheus-operator-crd-full) and we generate jsonnet code that can
|
||||
# be used to patch the "default" jsonnet CRD.
|
||||
.PHONY: generate-crds
|
||||
generate-crds: $(CONTROLLER_GEN_BINARY) $(GOJSONTOYAML_BINARY) $(TYPES_V1_TARGET) $(TYPES_V1ALPHA1_TARGET)
|
||||
cd pkg/apis/monitoring && $(CONTROLLER_GEN_BINARY) crd:crdVersions=v1 paths=./... output:crd:dir=$(PWD)/example/prometheus-operator-crd
|
||||
generate-crds: $(CONTROLLER_GEN_BINARY) $(GOJSONTOYAML_BINARY) $(TYPES_V1_TARGET) $(TYPES_V1ALPHA1_TARGET) $(TYPES_V1BETA1_TARGET)
|
||||
cd pkg/apis/monitoring && $(CONTROLLER_GEN_BINARY) crd:crdVersions=v1 paths=./v1/. paths=./v1alpha1/. output:crd:dir=$(PWD)/example/prometheus-operator-crd/
|
||||
find example/prometheus-operator-crd/ -name '*.yaml' -print0 | xargs -0 -I{} sh -c '$(GOJSONTOYAML_BINARY) -yamltojson < "$$1" | jq > "$(PWD)/jsonnet/prometheus-operator/$$(basename $$1 | cut -d'_' -f2 | cut -d. -f1)-crd.json"' -- {}
|
||||
|
||||
cd pkg/apis/monitoring && $(CONTROLLER_GEN_BINARY) crd:crdVersions=v1 paths=./... output:crd:dir=$(PWD)/example/prometheus-operator-crd-full
|
||||
echo "{spec+: {versions+: $$($(GOJSONTOYAML_BINARY) -yamltojson < example/prometheus-operator-crd-full/monitoring.coreos.com_alertmanagerconfigs.yaml | jq '.spec.versions | map(select(.name == "v1beta1"))')}}" | $(JSONNETFMT_BINARY) - > $(PWD)/jsonnet/prometheus-operator/alertmanagerconfigs-v1beta1-crd.libsonnet
|
||||
|
||||
.PHONY: generate-remote-write-certs
|
||||
generate-remote-write-certs:
|
||||
|
@ -234,12 +244,18 @@ example/thanos/thanos.yaml: scripts/generate/vendor scripts/generate/thanos.json
|
|||
example/admission-webhook: scripts/generate/vendor scripts/generate/admission-webhook.jsonnet $(shell find jsonnet -type f)
|
||||
scripts/generate/build-admission-webhook-example.sh
|
||||
|
||||
example/alertmanager-crd-conversion: scripts/generate/vendor scripts/generate/conversion-webhook-patch-for-alermanagerconfig-crd.jsonnet $(shell find jsonnet -type f)
|
||||
scripts/generate/build-conversion-webhook-patch-for-alermanagerconfig-crd.sh
|
||||
|
||||
FULLY_GENERATED_DOCS = Documentation/api.md Documentation/compatibility.md Documentation/operator.md
|
||||
TO_BE_EXTENDED_DOCS = $(filter-out $(FULLY_GENERATED_DOCS), $(shell find Documentation -type f))
|
||||
|
||||
Documentation/operator.md: operator
|
||||
$(MDOX_BINARY) fmt $@
|
||||
|
||||
# For now, the v1beta1 CRDs aren't part of the default bundle because they
|
||||
# require to deploy/run the conversion webhook. As a consequence, they are not
|
||||
# yet included in the API documentation.
|
||||
Documentation/api.md: $(PO_DOCGEN_BINARY) $(TYPES_V1_TARGET) $(TYPES_V1ALPHA1_TARGET)
|
||||
$(PO_DOCGEN_BINARY) api $(TYPES_V1_TARGET) $(TYPES_V1ALPHA1_TARGET) > $@
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ metadata:
|
|||
name: prometheus-operator-admission-webhook
|
||||
namespace: default
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
|
|
30
example/alertmanager-crd-conversion/patch.json
Normal file
30
example/alertmanager-crd-conversion/patch.json
Normal file
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"apiVersion": "apiextensions.k8s.io/v1",
|
||||
"kind": "CustomResourceDefinition",
|
||||
"metadata": {
|
||||
"annotations": {
|
||||
"controller-gen.kubebuilder.io/version": "v0.8.0"
|
||||
},
|
||||
"creationTimestamp": null,
|
||||
"name": "alertmanagerconfigs.monitoring.coreos.com"
|
||||
},
|
||||
"spec": {
|
||||
"conversion": {
|
||||
"strategy": "Webhook",
|
||||
"webhook": {
|
||||
"clientConfig": {
|
||||
"service": {
|
||||
"name": "prometheus-operator-admission-webhook",
|
||||
"namespace": "default",
|
||||
"path": "/convert",
|
||||
"port": 8443
|
||||
}
|
||||
},
|
||||
"conversionReviewVersions": [
|
||||
"v1beta1",
|
||||
"v1alpha1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,627 @@
|
|||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.8.0
|
||||
creationTimestamp: null
|
||||
name: podmonitors.monitoring.coreos.com
|
||||
spec:
|
||||
group: monitoring.coreos.com
|
||||
names:
|
||||
categories:
|
||||
- prometheus-operator
|
||||
kind: PodMonitor
|
||||
listKind: PodMonitorList
|
||||
plural: podmonitors
|
||||
shortNames:
|
||||
- pmon
|
||||
singular: podmonitor
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: PodMonitor defines monitoring for a set of pods.
|
||||
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: Specification of desired Pod selection for target discovery
|
||||
by Prometheus.
|
||||
properties:
|
||||
attachMetadata:
|
||||
description: 'Attaches node metadata to discovered targets. Only valid
|
||||
for role: pod. Only valid in Prometheus versions 2.35.0 and newer.'
|
||||
properties:
|
||||
node:
|
||||
description: When set to true, Prometheus must have permissions
|
||||
to get Nodes.
|
||||
type: boolean
|
||||
type: object
|
||||
jobLabel:
|
||||
description: The label to use to retrieve the job name from.
|
||||
type: string
|
||||
labelLimit:
|
||||
description: Per-scrape limit on number of labels that will be accepted
|
||||
for a sample. Only valid in Prometheus versions 2.27.0 and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
labelNameLengthLimit:
|
||||
description: Per-scrape limit on length of labels name that will be
|
||||
accepted for a sample. Only valid in Prometheus versions 2.27.0
|
||||
and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
labelValueLengthLimit:
|
||||
description: Per-scrape limit on length of labels value that will
|
||||
be accepted for a sample. Only valid in Prometheus versions 2.27.0
|
||||
and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
namespaceSelector:
|
||||
description: Selector to select which namespaces the Endpoints objects
|
||||
are discovered from.
|
||||
properties:
|
||||
any:
|
||||
description: Boolean describing whether all namespaces are selected
|
||||
in contrast to a list restricting them.
|
||||
type: boolean
|
||||
matchNames:
|
||||
description: List of namespace names to select from.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
podMetricsEndpoints:
|
||||
description: A list of endpoints allowed as part of this PodMonitor.
|
||||
items:
|
||||
description: PodMetricsEndpoint defines a scrapeable endpoint of
|
||||
a Kubernetes Pod serving Prometheus metrics.
|
||||
properties:
|
||||
authorization:
|
||||
description: Authorization section for this endpoint
|
||||
properties:
|
||||
credentials:
|
||||
description: The secret's key that contains the credentials
|
||||
of the request
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type:
|
||||
description: Set the authentication type. Defaults to Bearer,
|
||||
Basic will cause an error
|
||||
type: string
|
||||
type: object
|
||||
basicAuth:
|
||||
description: 'BasicAuth allow an endpoint to authenticate over
|
||||
basic authentication. More info: https://prometheus.io/docs/operating/configuration/#endpoint'
|
||||
properties:
|
||||
password:
|
||||
description: The secret in the service monitor namespace
|
||||
that contains the password for authentication.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
username:
|
||||
description: The secret in the service monitor namespace
|
||||
that contains the username for authentication.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
bearerTokenSecret:
|
||||
description: Secret to mount to read bearer token for scraping
|
||||
targets. The secret needs to be in the same namespace as the
|
||||
pod monitor and accessible by the Prometheus Operator.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
followRedirects:
|
||||
description: FollowRedirects configures whether scrape requests
|
||||
follow HTTP 3xx redirects.
|
||||
type: boolean
|
||||
honorLabels:
|
||||
description: HonorLabels chooses the metric's labels on collisions
|
||||
with target labels.
|
||||
type: boolean
|
||||
honorTimestamps:
|
||||
description: HonorTimestamps controls whether Prometheus respects
|
||||
the timestamps present in scraped data.
|
||||
type: boolean
|
||||
interval:
|
||||
description: Interval at which metrics should be scraped If
|
||||
not specified Prometheus' global scrape interval is used.
|
||||
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
|
||||
type: string
|
||||
metricRelabelings:
|
||||
description: MetricRelabelConfigs to apply to samples before
|
||||
ingestion.
|
||||
items:
|
||||
description: 'RelabelConfig allows dynamic rewriting of the
|
||||
label set, being applied to samples before ingestion. It
|
||||
defines `<metric_relabel_configs>`-section of Prometheus
|
||||
configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
|
||||
properties:
|
||||
action:
|
||||
default: replace
|
||||
description: Action to perform based on regex matching.
|
||||
Default is 'replace'
|
||||
enum:
|
||||
- replace
|
||||
- keep
|
||||
- drop
|
||||
- hashmod
|
||||
- labelmap
|
||||
- labeldrop
|
||||
- labelkeep
|
||||
type: string
|
||||
modulus:
|
||||
description: Modulus to take of the hash of the source
|
||||
label values.
|
||||
format: int64
|
||||
type: integer
|
||||
regex:
|
||||
description: Regular expression against which the extracted
|
||||
value is matched. Default is '(.*)'
|
||||
type: string
|
||||
replacement:
|
||||
description: Replacement value against which a regex replace
|
||||
is performed if the regular expression matches. Regex
|
||||
capture groups are available. Default is '$1'
|
||||
type: string
|
||||
separator:
|
||||
description: Separator placed between concatenated source
|
||||
label values. default is ';'.
|
||||
type: string
|
||||
sourceLabels:
|
||||
description: The source labels select values from existing
|
||||
labels. Their content is concatenated using the configured
|
||||
separator and matched against the configured regular
|
||||
expression for the replace, keep, and drop actions.
|
||||
items:
|
||||
description: LabelName is a valid Prometheus label name
|
||||
which may only contain ASCII letters, numbers, as
|
||||
well as underscores.
|
||||
pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
|
||||
type: string
|
||||
type: array
|
||||
targetLabel:
|
||||
description: Label to which the resulting value is written
|
||||
in a replace action. It is mandatory for replace actions.
|
||||
Regex capture groups are available.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
oauth2:
|
||||
description: OAuth2 for the URL. Only valid in Prometheus versions
|
||||
2.27.0 and newer.
|
||||
properties:
|
||||
clientId:
|
||||
description: The secret or configmap containing the OAuth2
|
||||
client id
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the
|
||||
targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its
|
||||
key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
clientSecret:
|
||||
description: The secret containing the OAuth2 client secret
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
endpointParams:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Parameters to append to the token URL
|
||||
type: object
|
||||
scopes:
|
||||
description: OAuth2 scopes used for the token request
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
tokenUrl:
|
||||
description: The URL to fetch the token from
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- clientId
|
||||
- clientSecret
|
||||
- tokenUrl
|
||||
type: object
|
||||
params:
|
||||
additionalProperties:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
description: Optional HTTP URL parameters
|
||||
type: object
|
||||
path:
|
||||
description: HTTP path to scrape for metrics.
|
||||
type: string
|
||||
port:
|
||||
description: Name of the pod port this endpoint refers to. Mutually
|
||||
exclusive with targetPort.
|
||||
type: string
|
||||
proxyUrl:
|
||||
description: ProxyURL eg http://proxyserver:2195 Directs scrapes
|
||||
to proxy through this endpoint.
|
||||
type: string
|
||||
relabelings:
|
||||
description: 'RelabelConfigs to apply to samples before scraping.
|
||||
Prometheus Operator automatically adds relabelings for a few
|
||||
standard Kubernetes fields. The original scrape job''s name
|
||||
is available via the `__tmp_prometheus_job_name` label. More
|
||||
info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config'
|
||||
items:
|
||||
description: 'RelabelConfig allows dynamic rewriting of the
|
||||
label set, being applied to samples before ingestion. It
|
||||
defines `<metric_relabel_configs>`-section of Prometheus
|
||||
configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
|
||||
properties:
|
||||
action:
|
||||
default: replace
|
||||
description: Action to perform based on regex matching.
|
||||
Default is 'replace'
|
||||
enum:
|
||||
- replace
|
||||
- keep
|
||||
- drop
|
||||
- hashmod
|
||||
- labelmap
|
||||
- labeldrop
|
||||
- labelkeep
|
||||
type: string
|
||||
modulus:
|
||||
description: Modulus to take of the hash of the source
|
||||
label values.
|
||||
format: int64
|
||||
type: integer
|
||||
regex:
|
||||
description: Regular expression against which the extracted
|
||||
value is matched. Default is '(.*)'
|
||||
type: string
|
||||
replacement:
|
||||
description: Replacement value against which a regex replace
|
||||
is performed if the regular expression matches. Regex
|
||||
capture groups are available. Default is '$1'
|
||||
type: string
|
||||
separator:
|
||||
description: Separator placed between concatenated source
|
||||
label values. default is ';'.
|
||||
type: string
|
||||
sourceLabels:
|
||||
description: The source labels select values from existing
|
||||
labels. Their content is concatenated using the configured
|
||||
separator and matched against the configured regular
|
||||
expression for the replace, keep, and drop actions.
|
||||
items:
|
||||
description: LabelName is a valid Prometheus label name
|
||||
which may only contain ASCII letters, numbers, as
|
||||
well as underscores.
|
||||
pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
|
||||
type: string
|
||||
type: array
|
||||
targetLabel:
|
||||
description: Label to which the resulting value is written
|
||||
in a replace action. It is mandatory for replace actions.
|
||||
Regex capture groups are available.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
scheme:
|
||||
description: HTTP scheme to use for scraping.
|
||||
type: string
|
||||
scrapeTimeout:
|
||||
description: Timeout after which the scrape is ended If not
|
||||
specified, the Prometheus global scrape interval is used.
|
||||
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
|
||||
type: string
|
||||
targetPort:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: 'Deprecated: Use ''port'' instead.'
|
||||
x-kubernetes-int-or-string: true
|
||||
tlsConfig:
|
||||
description: TLS configuration to use when scraping the endpoint.
|
||||
properties:
|
||||
ca:
|
||||
description: Struct containing the CA cert to use for the
|
||||
targets.
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the
|
||||
targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its
|
||||
key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
cert:
|
||||
description: Struct containing the client cert file for
|
||||
the targets.
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the
|
||||
targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its
|
||||
key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
description: Disable target certificate validation.
|
||||
type: boolean
|
||||
keySecret:
|
||||
description: Secret containing the client key file for the
|
||||
targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
serverName:
|
||||
description: Used to verify the hostname for the targets.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
podTargetLabels:
|
||||
description: PodTargetLabels transfers labels on the Kubernetes Pod
|
||||
onto the target.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
sampleLimit:
|
||||
description: SampleLimit defines per-scrape limit on number of scraped
|
||||
samples that will be accepted.
|
||||
format: int64
|
||||
type: integer
|
||||
selector:
|
||||
description: Selector to select Pod objects.
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector requirements.
|
||||
The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a selector that
|
||||
contains values, a key, and an operator that relates the key
|
||||
and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector applies
|
||||
to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship to
|
||||
a set of values. Valid operators are In, NotIn, Exists
|
||||
and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string values. If the
|
||||
operator is In or NotIn, the values array must be non-empty.
|
||||
If the operator is Exists or DoesNotExist, the values
|
||||
array must be empty. This array is replaced during a strategic
|
||||
merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value} pairs. A single
|
||||
{key,value} in the matchLabels map is equivalent to an element
|
||||
of matchExpressions, whose key field is "key", the operator
|
||||
is "In", and the values array contains only "value". The requirements
|
||||
are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
targetLimit:
|
||||
description: TargetLimit defines a limit on the number of scraped
|
||||
targets that will be accepted.
|
||||
format: int64
|
||||
type: integer
|
||||
required:
|
||||
- podMetricsEndpoints
|
||||
- selector
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
|
@ -0,0 +1,659 @@
|
|||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.8.0
|
||||
creationTimestamp: null
|
||||
name: probes.monitoring.coreos.com
|
||||
spec:
|
||||
group: monitoring.coreos.com
|
||||
names:
|
||||
categories:
|
||||
- prometheus-operator
|
||||
kind: Probe
|
||||
listKind: ProbeList
|
||||
plural: probes
|
||||
shortNames:
|
||||
- prb
|
||||
singular: probe
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Probe defines monitoring for a set of static targets or ingresses.
|
||||
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: Specification of desired Ingress selection for target discovery
|
||||
by Prometheus.
|
||||
properties:
|
||||
authorization:
|
||||
description: Authorization section for this endpoint
|
||||
properties:
|
||||
credentials:
|
||||
description: The secret's key that contains the credentials of
|
||||
the request
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be
|
||||
a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be
|
||||
defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type:
|
||||
description: Set the authentication type. Defaults to Bearer,
|
||||
Basic will cause an error
|
||||
type: string
|
||||
type: object
|
||||
basicAuth:
|
||||
description: 'BasicAuth allow an endpoint to authenticate over basic
|
||||
authentication. More info: https://prometheus.io/docs/operating/configuration/#endpoint'
|
||||
properties:
|
||||
password:
|
||||
description: The secret in the service monitor namespace that
|
||||
contains the password for authentication.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be
|
||||
a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be
|
||||
defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
username:
|
||||
description: The secret in the service monitor namespace that
|
||||
contains the username for authentication.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be
|
||||
a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be
|
||||
defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
bearerTokenSecret:
|
||||
description: Secret to mount to read bearer token for scraping targets.
|
||||
The secret needs to be in the same namespace as the probe and accessible
|
||||
by the Prometheus Operator.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be a
|
||||
valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
interval:
|
||||
description: Interval at which targets are probed using the configured
|
||||
prober. If not specified Prometheus' global scrape interval is used.
|
||||
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
|
||||
type: string
|
||||
jobName:
|
||||
description: The job name assigned to scraped metrics by default.
|
||||
type: string
|
||||
labelLimit:
|
||||
description: Per-scrape limit on number of labels that will be accepted
|
||||
for a sample. Only valid in Prometheus versions 2.27.0 and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
labelNameLengthLimit:
|
||||
description: Per-scrape limit on length of labels name that will be
|
||||
accepted for a sample. Only valid in Prometheus versions 2.27.0
|
||||
and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
labelValueLengthLimit:
|
||||
description: Per-scrape limit on length of labels value that will
|
||||
be accepted for a sample. Only valid in Prometheus versions 2.27.0
|
||||
and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
metricRelabelings:
|
||||
description: MetricRelabelConfigs to apply to samples before ingestion.
|
||||
items:
|
||||
description: 'RelabelConfig allows dynamic rewriting of the label
|
||||
set, being applied to samples before ingestion. It defines `<metric_relabel_configs>`-section
|
||||
of Prometheus configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
|
||||
properties:
|
||||
action:
|
||||
default: replace
|
||||
description: Action to perform based on regex matching. Default
|
||||
is 'replace'
|
||||
enum:
|
||||
- replace
|
||||
- keep
|
||||
- drop
|
||||
- hashmod
|
||||
- labelmap
|
||||
- labeldrop
|
||||
- labelkeep
|
||||
type: string
|
||||
modulus:
|
||||
description: Modulus to take of the hash of the source label
|
||||
values.
|
||||
format: int64
|
||||
type: integer
|
||||
regex:
|
||||
description: Regular expression against which the extracted
|
||||
value is matched. Default is '(.*)'
|
||||
type: string
|
||||
replacement:
|
||||
description: Replacement value against which a regex replace
|
||||
is performed if the regular expression matches. Regex capture
|
||||
groups are available. Default is '$1'
|
||||
type: string
|
||||
separator:
|
||||
description: Separator placed between concatenated source label
|
||||
values. default is ';'.
|
||||
type: string
|
||||
sourceLabels:
|
||||
description: The source labels select values from existing labels.
|
||||
Their content is concatenated using the configured separator
|
||||
and matched against the configured regular expression for
|
||||
the replace, keep, and drop actions.
|
||||
items:
|
||||
description: LabelName is a valid Prometheus label name which
|
||||
may only contain ASCII letters, numbers, as well as underscores.
|
||||
pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
|
||||
type: string
|
||||
type: array
|
||||
targetLabel:
|
||||
description: Label to which the resulting value is written in
|
||||
a replace action. It is mandatory for replace actions. Regex
|
||||
capture groups are available.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
module:
|
||||
description: 'The module to use for probing specifying how to probe
|
||||
the target. Example module configuring in the blackbox exporter:
|
||||
https://github.com/prometheus/blackbox_exporter/blob/master/example.yml'
|
||||
type: string
|
||||
oauth2:
|
||||
description: OAuth2 for the URL. Only valid in Prometheus versions
|
||||
2.27.0 and newer.
|
||||
properties:
|
||||
clientId:
|
||||
description: The secret or configmap containing the OAuth2 client
|
||||
id
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
clientSecret:
|
||||
description: The secret containing the OAuth2 client secret
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be
|
||||
a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be
|
||||
defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
endpointParams:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Parameters to append to the token URL
|
||||
type: object
|
||||
scopes:
|
||||
description: OAuth2 scopes used for the token request
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
tokenUrl:
|
||||
description: The URL to fetch the token from
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- clientId
|
||||
- clientSecret
|
||||
- tokenUrl
|
||||
type: object
|
||||
prober:
|
||||
description: Specification for the prober to use for probing targets.
|
||||
The prober.URL parameter is required. Targets cannot be probed if
|
||||
left empty.
|
||||
properties:
|
||||
path:
|
||||
description: Path to collect metrics from. Defaults to `/probe`.
|
||||
type: string
|
||||
proxyUrl:
|
||||
description: Optional ProxyURL.
|
||||
type: string
|
||||
scheme:
|
||||
description: HTTP scheme to use for scraping. Defaults to `http`.
|
||||
type: string
|
||||
url:
|
||||
description: Mandatory URL of the prober.
|
||||
type: string
|
||||
required:
|
||||
- url
|
||||
type: object
|
||||
sampleLimit:
|
||||
description: SampleLimit defines per-scrape limit on number of scraped
|
||||
samples that will be accepted.
|
||||
format: int64
|
||||
type: integer
|
||||
scrapeTimeout:
|
||||
description: Timeout for scraping metrics from the Prometheus exporter.
|
||||
If not specified, the Prometheus global scrape interval is used.
|
||||
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
|
||||
type: string
|
||||
targetLimit:
|
||||
description: TargetLimit defines a limit on the number of scraped
|
||||
targets that will be accepted.
|
||||
format: int64
|
||||
type: integer
|
||||
targets:
|
||||
description: Targets defines a set of static or dynamically discovered
|
||||
targets to probe.
|
||||
properties:
|
||||
ingress:
|
||||
description: ingress defines the Ingress objects to probe and
|
||||
the relabeling configuration. If `staticConfig` is also defined,
|
||||
`staticConfig` takes precedence.
|
||||
properties:
|
||||
namespaceSelector:
|
||||
description: From which namespaces to select Ingress objects.
|
||||
properties:
|
||||
any:
|
||||
description: Boolean describing whether all namespaces
|
||||
are selected in contrast to a list restricting them.
|
||||
type: boolean
|
||||
matchNames:
|
||||
description: List of namespace names to select from.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
relabelingConfigs:
|
||||
description: 'RelabelConfigs to apply to the label set of
|
||||
the target before it gets scraped. The original ingress
|
||||
address is available via the `__tmp_prometheus_ingress_address`
|
||||
label. It can be used to customize the probed URL. The original
|
||||
scrape job''s name is available via the `__tmp_prometheus_job_name`
|
||||
label. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config'
|
||||
items:
|
||||
description: 'RelabelConfig allows dynamic rewriting of
|
||||
the label set, being applied to samples before ingestion.
|
||||
It defines `<metric_relabel_configs>`-section of Prometheus
|
||||
configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
|
||||
properties:
|
||||
action:
|
||||
default: replace
|
||||
description: Action to perform based on regex matching.
|
||||
Default is 'replace'
|
||||
enum:
|
||||
- replace
|
||||
- keep
|
||||
- drop
|
||||
- hashmod
|
||||
- labelmap
|
||||
- labeldrop
|
||||
- labelkeep
|
||||
type: string
|
||||
modulus:
|
||||
description: Modulus to take of the hash of the source
|
||||
label values.
|
||||
format: int64
|
||||
type: integer
|
||||
regex:
|
||||
description: Regular expression against which the extracted
|
||||
value is matched. Default is '(.*)'
|
||||
type: string
|
||||
replacement:
|
||||
description: Replacement value against which a regex
|
||||
replace is performed if the regular expression matches.
|
||||
Regex capture groups are available. Default is '$1'
|
||||
type: string
|
||||
separator:
|
||||
description: Separator placed between concatenated source
|
||||
label values. default is ';'.
|
||||
type: string
|
||||
sourceLabels:
|
||||
description: The source labels select values from existing
|
||||
labels. Their content is concatenated using the configured
|
||||
separator and matched against the configured regular
|
||||
expression for the replace, keep, and drop actions.
|
||||
items:
|
||||
description: LabelName is a valid Prometheus label
|
||||
name which may only contain ASCII letters, numbers,
|
||||
as well as underscores.
|
||||
pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
|
||||
type: string
|
||||
type: array
|
||||
targetLabel:
|
||||
description: Label to which the resulting value is written
|
||||
in a replace action. It is mandatory for replace actions.
|
||||
Regex capture groups are available.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
selector:
|
||||
description: Selector to select the Ingress objects.
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector
|
||||
requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a selector
|
||||
that contains values, a key, and an operator that
|
||||
relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector
|
||||
applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are In, NotIn,
|
||||
Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string values.
|
||||
If the operator is In or NotIn, the values array
|
||||
must be non-empty. If the operator is Exists or
|
||||
DoesNotExist, the values array must be empty.
|
||||
This array is replaced during a strategic merge
|
||||
patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value} pairs.
|
||||
A single {key,value} in the matchLabels map is equivalent
|
||||
to an element of matchExpressions, whose key field is
|
||||
"key", the operator is "In", and the values array contains
|
||||
only "value". The requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
staticConfig:
|
||||
description: 'staticConfig defines the static list of targets
|
||||
to probe and the relabeling configuration. If `ingress` is also
|
||||
defined, `staticConfig` takes precedence. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#static_config.'
|
||||
properties:
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Labels assigned to all metrics scraped from the
|
||||
targets.
|
||||
type: object
|
||||
relabelingConfigs:
|
||||
description: 'RelabelConfigs to apply to the label set of
|
||||
the targets before it gets scraped. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config'
|
||||
items:
|
||||
description: 'RelabelConfig allows dynamic rewriting of
|
||||
the label set, being applied to samples before ingestion.
|
||||
It defines `<metric_relabel_configs>`-section of Prometheus
|
||||
configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
|
||||
properties:
|
||||
action:
|
||||
default: replace
|
||||
description: Action to perform based on regex matching.
|
||||
Default is 'replace'
|
||||
enum:
|
||||
- replace
|
||||
- keep
|
||||
- drop
|
||||
- hashmod
|
||||
- labelmap
|
||||
- labeldrop
|
||||
- labelkeep
|
||||
type: string
|
||||
modulus:
|
||||
description: Modulus to take of the hash of the source
|
||||
label values.
|
||||
format: int64
|
||||
type: integer
|
||||
regex:
|
||||
description: Regular expression against which the extracted
|
||||
value is matched. Default is '(.*)'
|
||||
type: string
|
||||
replacement:
|
||||
description: Replacement value against which a regex
|
||||
replace is performed if the regular expression matches.
|
||||
Regex capture groups are available. Default is '$1'
|
||||
type: string
|
||||
separator:
|
||||
description: Separator placed between concatenated source
|
||||
label values. default is ';'.
|
||||
type: string
|
||||
sourceLabels:
|
||||
description: The source labels select values from existing
|
||||
labels. Their content is concatenated using the configured
|
||||
separator and matched against the configured regular
|
||||
expression for the replace, keep, and drop actions.
|
||||
items:
|
||||
description: LabelName is a valid Prometheus label
|
||||
name which may only contain ASCII letters, numbers,
|
||||
as well as underscores.
|
||||
pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
|
||||
type: string
|
||||
type: array
|
||||
targetLabel:
|
||||
description: Label to which the resulting value is written
|
||||
in a replace action. It is mandatory for replace actions.
|
||||
Regex capture groups are available.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
static:
|
||||
description: The list of hosts to probe.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
tlsConfig:
|
||||
description: TLS configuration to use when scraping the endpoint.
|
||||
properties:
|
||||
ca:
|
||||
description: Struct containing the CA cert to use for the targets.
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
cert:
|
||||
description: Struct containing the client cert file for the targets.
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
insecureSkipVerify:
|
||||
description: Disable target certificate validation.
|
||||
type: boolean
|
||||
keySecret:
|
||||
description: Secret containing the client key file for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be
|
||||
a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be
|
||||
defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
serverName:
|
||||
description: Used to verify the hostname for the targets.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.8.0
|
||||
creationTimestamp: null
|
||||
name: prometheusrules.monitoring.coreos.com
|
||||
spec:
|
||||
group: monitoring.coreos.com
|
||||
names:
|
||||
categories:
|
||||
- prometheus-operator
|
||||
kind: PrometheusRule
|
||||
listKind: PrometheusRuleList
|
||||
plural: prometheusrules
|
||||
shortNames:
|
||||
- promrule
|
||||
singular: prometheusrule
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: PrometheusRule defines recording and alerting rules for a Prometheus
|
||||
instance
|
||||
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: Specification of desired alerting rule definitions for Prometheus.
|
||||
properties:
|
||||
groups:
|
||||
description: Content of Prometheus rule file
|
||||
items:
|
||||
description: 'RuleGroup is a list of sequentially evaluated recording
|
||||
and alerting rules. Note: PartialResponseStrategy is only used
|
||||
by ThanosRuler and will be ignored by Prometheus instances. Valid
|
||||
values for this field are ''warn'' or ''abort''. More info: https://github.com/thanos-io/thanos/blob/main/docs/components/rule.md#partial-response'
|
||||
properties:
|
||||
interval:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
partial_response_strategy:
|
||||
type: string
|
||||
rules:
|
||||
items:
|
||||
description: 'Rule describes an alerting or recording rule
|
||||
See Prometheus documentation: [alerting](https://www.prometheus.io/docs/prometheus/latest/configuration/alerting_rules/)
|
||||
or [recording](https://www.prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules)
|
||||
rule'
|
||||
properties:
|
||||
alert:
|
||||
type: string
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
expr:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
x-kubernetes-int-or-string: true
|
||||
for:
|
||||
type: string
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
record:
|
||||
type: string
|
||||
required:
|
||||
- expr
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- name
|
||||
- rules
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
|
@ -0,0 +1,645 @@
|
|||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.8.0
|
||||
creationTimestamp: null
|
||||
name: servicemonitors.monitoring.coreos.com
|
||||
spec:
|
||||
group: monitoring.coreos.com
|
||||
names:
|
||||
categories:
|
||||
- prometheus-operator
|
||||
kind: ServiceMonitor
|
||||
listKind: ServiceMonitorList
|
||||
plural: servicemonitors
|
||||
shortNames:
|
||||
- smon
|
||||
singular: servicemonitor
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: ServiceMonitor defines monitoring for a set of services.
|
||||
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: Specification of desired Service selection for target discovery
|
||||
by Prometheus.
|
||||
properties:
|
||||
endpoints:
|
||||
description: A list of endpoints allowed as part of this ServiceMonitor.
|
||||
items:
|
||||
description: Endpoint defines a scrapeable endpoint serving Prometheus
|
||||
metrics.
|
||||
properties:
|
||||
authorization:
|
||||
description: Authorization section for this endpoint
|
||||
properties:
|
||||
credentials:
|
||||
description: The secret's key that contains the credentials
|
||||
of the request
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type:
|
||||
description: Set the authentication type. Defaults to Bearer,
|
||||
Basic will cause an error
|
||||
type: string
|
||||
type: object
|
||||
basicAuth:
|
||||
description: 'BasicAuth allow an endpoint to authenticate over
|
||||
basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints'
|
||||
properties:
|
||||
password:
|
||||
description: The secret in the service monitor namespace
|
||||
that contains the password for authentication.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
username:
|
||||
description: The secret in the service monitor namespace
|
||||
that contains the username for authentication.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
bearerTokenFile:
|
||||
description: File to read bearer token for scraping targets.
|
||||
type: string
|
||||
bearerTokenSecret:
|
||||
description: Secret to mount to read bearer token for scraping
|
||||
targets. The secret needs to be in the same namespace as the
|
||||
service monitor and accessible by the Prometheus Operator.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
followRedirects:
|
||||
description: FollowRedirects configures whether scrape requests
|
||||
follow HTTP 3xx redirects.
|
||||
type: boolean
|
||||
honorLabels:
|
||||
description: HonorLabels chooses the metric's labels on collisions
|
||||
with target labels.
|
||||
type: boolean
|
||||
honorTimestamps:
|
||||
description: HonorTimestamps controls whether Prometheus respects
|
||||
the timestamps present in scraped data.
|
||||
type: boolean
|
||||
interval:
|
||||
description: Interval at which metrics should be scraped If
|
||||
not specified Prometheus' global scrape interval is used.
|
||||
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
|
||||
type: string
|
||||
metricRelabelings:
|
||||
description: MetricRelabelConfigs to apply to samples before
|
||||
ingestion.
|
||||
items:
|
||||
description: 'RelabelConfig allows dynamic rewriting of the
|
||||
label set, being applied to samples before ingestion. It
|
||||
defines `<metric_relabel_configs>`-section of Prometheus
|
||||
configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
|
||||
properties:
|
||||
action:
|
||||
default: replace
|
||||
description: Action to perform based on regex matching.
|
||||
Default is 'replace'
|
||||
enum:
|
||||
- replace
|
||||
- keep
|
||||
- drop
|
||||
- hashmod
|
||||
- labelmap
|
||||
- labeldrop
|
||||
- labelkeep
|
||||
type: string
|
||||
modulus:
|
||||
description: Modulus to take of the hash of the source
|
||||
label values.
|
||||
format: int64
|
||||
type: integer
|
||||
regex:
|
||||
description: Regular expression against which the extracted
|
||||
value is matched. Default is '(.*)'
|
||||
type: string
|
||||
replacement:
|
||||
description: Replacement value against which a regex replace
|
||||
is performed if the regular expression matches. Regex
|
||||
capture groups are available. Default is '$1'
|
||||
type: string
|
||||
separator:
|
||||
description: Separator placed between concatenated source
|
||||
label values. default is ';'.
|
||||
type: string
|
||||
sourceLabels:
|
||||
description: The source labels select values from existing
|
||||
labels. Their content is concatenated using the configured
|
||||
separator and matched against the configured regular
|
||||
expression for the replace, keep, and drop actions.
|
||||
items:
|
||||
description: LabelName is a valid Prometheus label name
|
||||
which may only contain ASCII letters, numbers, as
|
||||
well as underscores.
|
||||
pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
|
||||
type: string
|
||||
type: array
|
||||
targetLabel:
|
||||
description: Label to which the resulting value is written
|
||||
in a replace action. It is mandatory for replace actions.
|
||||
Regex capture groups are available.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
oauth2:
|
||||
description: OAuth2 for the URL. Only valid in Prometheus versions
|
||||
2.27.0 and newer.
|
||||
properties:
|
||||
clientId:
|
||||
description: The secret or configmap containing the OAuth2
|
||||
client id
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the
|
||||
targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its
|
||||
key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
clientSecret:
|
||||
description: The secret containing the OAuth2 client secret
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
endpointParams:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Parameters to append to the token URL
|
||||
type: object
|
||||
scopes:
|
||||
description: OAuth2 scopes used for the token request
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
tokenUrl:
|
||||
description: The URL to fetch the token from
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- clientId
|
||||
- clientSecret
|
||||
- tokenUrl
|
||||
type: object
|
||||
params:
|
||||
additionalProperties:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
description: Optional HTTP URL parameters
|
||||
type: object
|
||||
path:
|
||||
description: HTTP path to scrape for metrics.
|
||||
type: string
|
||||
port:
|
||||
description: Name of the service port this endpoint refers to.
|
||||
Mutually exclusive with targetPort.
|
||||
type: string
|
||||
proxyUrl:
|
||||
description: ProxyURL eg http://proxyserver:2195 Directs scrapes
|
||||
to proxy through this endpoint.
|
||||
type: string
|
||||
relabelings:
|
||||
description: 'RelabelConfigs to apply to samples before scraping.
|
||||
Prometheus Operator automatically adds relabelings for a few
|
||||
standard Kubernetes fields. The original scrape job''s name
|
||||
is available via the `__tmp_prometheus_job_name` label. More
|
||||
info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config'
|
||||
items:
|
||||
description: 'RelabelConfig allows dynamic rewriting of the
|
||||
label set, being applied to samples before ingestion. It
|
||||
defines `<metric_relabel_configs>`-section of Prometheus
|
||||
configuration. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs'
|
||||
properties:
|
||||
action:
|
||||
default: replace
|
||||
description: Action to perform based on regex matching.
|
||||
Default is 'replace'
|
||||
enum:
|
||||
- replace
|
||||
- keep
|
||||
- drop
|
||||
- hashmod
|
||||
- labelmap
|
||||
- labeldrop
|
||||
- labelkeep
|
||||
type: string
|
||||
modulus:
|
||||
description: Modulus to take of the hash of the source
|
||||
label values.
|
||||
format: int64
|
||||
type: integer
|
||||
regex:
|
||||
description: Regular expression against which the extracted
|
||||
value is matched. Default is '(.*)'
|
||||
type: string
|
||||
replacement:
|
||||
description: Replacement value against which a regex replace
|
||||
is performed if the regular expression matches. Regex
|
||||
capture groups are available. Default is '$1'
|
||||
type: string
|
||||
separator:
|
||||
description: Separator placed between concatenated source
|
||||
label values. default is ';'.
|
||||
type: string
|
||||
sourceLabels:
|
||||
description: The source labels select values from existing
|
||||
labels. Their content is concatenated using the configured
|
||||
separator and matched against the configured regular
|
||||
expression for the replace, keep, and drop actions.
|
||||
items:
|
||||
description: LabelName is a valid Prometheus label name
|
||||
which may only contain ASCII letters, numbers, as
|
||||
well as underscores.
|
||||
pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
|
||||
type: string
|
||||
type: array
|
||||
targetLabel:
|
||||
description: Label to which the resulting value is written
|
||||
in a replace action. It is mandatory for replace actions.
|
||||
Regex capture groups are available.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
scheme:
|
||||
description: HTTP scheme to use for scraping.
|
||||
type: string
|
||||
scrapeTimeout:
|
||||
description: Timeout after which the scrape is ended If not
|
||||
specified, the Prometheus global scrape timeout is used unless
|
||||
it is less than `Interval` in which the latter is used.
|
||||
pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
|
||||
type: string
|
||||
targetPort:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: Name or number of the target port of the Pod behind
|
||||
the Service, the port must be specified with container port
|
||||
property. Mutually exclusive with port.
|
||||
x-kubernetes-int-or-string: true
|
||||
tlsConfig:
|
||||
description: TLS configuration to use when scraping the endpoint
|
||||
properties:
|
||||
ca:
|
||||
description: Struct containing the CA cert to use for the
|
||||
targets.
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the
|
||||
targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its
|
||||
key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
caFile:
|
||||
description: Path to the CA cert in the Prometheus container
|
||||
to use for the targets.
|
||||
type: string
|
||||
cert:
|
||||
description: Struct containing the client cert file for
|
||||
the targets.
|
||||
properties:
|
||||
configMap:
|
||||
description: ConfigMap containing data to use for the
|
||||
targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its
|
||||
key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
secret:
|
||||
description: Secret containing data to use for the targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind,
|
||||
uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key
|
||||
must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
type: object
|
||||
certFile:
|
||||
description: Path to the client cert file in the Prometheus
|
||||
container for the targets.
|
||||
type: string
|
||||
insecureSkipVerify:
|
||||
description: Disable target certificate validation.
|
||||
type: boolean
|
||||
keyFile:
|
||||
description: Path to the client key file in the Prometheus
|
||||
container for the targets.
|
||||
type: string
|
||||
keySecret:
|
||||
description: Secret containing the client key file for the
|
||||
targets.
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must
|
||||
be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must
|
||||
be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
serverName:
|
||||
description: Used to verify the hostname for the targets.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
jobLabel:
|
||||
description: "Chooses the label of the Kubernetes `Endpoints`. Its
|
||||
value will be used for the `job`-label's value of the created metrics.
|
||||
\n Default & fallback value: the name of the respective Kubernetes
|
||||
`Endpoint`."
|
||||
type: string
|
||||
labelLimit:
|
||||
description: Per-scrape limit on number of labels that will be accepted
|
||||
for a sample. Only valid in Prometheus versions 2.27.0 and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
labelNameLengthLimit:
|
||||
description: Per-scrape limit on length of labels name that will be
|
||||
accepted for a sample. Only valid in Prometheus versions 2.27.0
|
||||
and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
labelValueLengthLimit:
|
||||
description: Per-scrape limit on length of labels value that will
|
||||
be accepted for a sample. Only valid in Prometheus versions 2.27.0
|
||||
and newer.
|
||||
format: int64
|
||||
type: integer
|
||||
namespaceSelector:
|
||||
description: Selector to select which namespaces the Kubernetes Endpoints
|
||||
objects are discovered from.
|
||||
properties:
|
||||
any:
|
||||
description: Boolean describing whether all namespaces are selected
|
||||
in contrast to a list restricting them.
|
||||
type: boolean
|
||||
matchNames:
|
||||
description: List of namespace names to select from.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
podTargetLabels:
|
||||
description: PodTargetLabels transfers labels on the Kubernetes `Pod`
|
||||
onto the created metrics.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
sampleLimit:
|
||||
description: SampleLimit defines per-scrape limit on number of scraped
|
||||
samples that will be accepted.
|
||||
format: int64
|
||||
type: integer
|
||||
selector:
|
||||
description: Selector to select Endpoints objects.
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector requirements.
|
||||
The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a selector that
|
||||
contains values, a key, and an operator that relates the key
|
||||
and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector applies
|
||||
to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship to
|
||||
a set of values. Valid operators are In, NotIn, Exists
|
||||
and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string values. If the
|
||||
operator is In or NotIn, the values array must be non-empty.
|
||||
If the operator is Exists or DoesNotExist, the values
|
||||
array must be empty. This array is replaced during a strategic
|
||||
merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value} pairs. A single
|
||||
{key,value} in the matchLabels map is equivalent to an element
|
||||
of matchExpressions, whose key field is "key", the operator
|
||||
is "In", and the values array contains only "value". The requirements
|
||||
are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
targetLabels:
|
||||
description: TargetLabels transfers labels from the Kubernetes `Service`
|
||||
onto the created metrics.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
targetLimit:
|
||||
description: TargetLimit defines a limit on the number of scraped
|
||||
targets that will be accepted.
|
||||
format: int64
|
||||
type: integer
|
||||
required:
|
||||
- endpoints
|
||||
- selector
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
File diff suppressed because it is too large
Load diff
6
go.mod
6
go.mod
|
@ -34,12 +34,13 @@ require (
|
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.24.1
|
||||
k8s.io/apiextensions-apiserver v0.23.3
|
||||
k8s.io/apiextensions-apiserver v0.23.5
|
||||
k8s.io/apimachinery v0.24.1
|
||||
k8s.io/client-go v0.24.1
|
||||
k8s.io/component-base v0.24.1
|
||||
k8s.io/klog/v2 v2.60.1
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
|
||||
sigs.k8s.io/controller-runtime v0.11.2
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -93,7 +94,6 @@ require (
|
|||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/onsi/gomega v1.16.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
|
@ -121,7 +121,7 @@ require (
|
|||
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
|
|
|
@ -21,7 +21,6 @@ local defaults = {
|
|||
},
|
||||
};
|
||||
|
||||
|
||||
function(params) {
|
||||
local aw = self,
|
||||
_config:: defaults + params,
|
||||
|
@ -47,7 +46,6 @@ function(params) {
|
|||
{ name: 'https', targetPort: 'https', port: aw._config.port },
|
||||
],
|
||||
selector: aw._config.selectorLabels,
|
||||
clusterIP: 'None',
|
||||
},
|
||||
},
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
39
jsonnet/prometheus-operator/conversion.libsonnet
Normal file
39
jsonnet/prometheus-operator/conversion.libsonnet
Normal file
|
@ -0,0 +1,39 @@
|
|||
local defaults = {
|
||||
local defaults = self,
|
||||
name: error 'must provide the name of the webhook service',
|
||||
namespace: error 'must provide the namespace of the webhook service',
|
||||
annotations: {},
|
||||
port: 8443,
|
||||
path: '/convert',
|
||||
versions: ['v1beta1', 'v1alpha1'],
|
||||
caBundle: '',
|
||||
};
|
||||
|
||||
|
||||
function(params) {
|
||||
local c = self,
|
||||
_config:: defaults + params,
|
||||
|
||||
metadata+: {
|
||||
annotations+: c._config.annotations,
|
||||
},
|
||||
spec+: {
|
||||
conversion: {
|
||||
strategy: 'Webhook',
|
||||
webhook: {
|
||||
conversionReviewVersions: c._config.versions,
|
||||
clientConfig: {
|
||||
service: {
|
||||
namespace: c._config.namespace,
|
||||
name: c._config.name,
|
||||
path: c._config.path,
|
||||
port: c._config.port,
|
||||
} + if c._config.caBundle != '' then
|
||||
{ caBundle: c._config.caBundle }
|
||||
else
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
|
@ -20,6 +20,7 @@ local defaults = {
|
|||
for labelName in std.objectFields(defaults.commonLabels)
|
||||
if !std.setMember(labelName, ['app.kubernetes.io/version'])
|
||||
},
|
||||
enableAlertmanagerConfigV1beta1: false,
|
||||
};
|
||||
|
||||
function(params) {
|
||||
|
@ -28,7 +29,10 @@ function(params) {
|
|||
|
||||
// Prefixing with 0 to ensure these manifests are listed and therefore created first.
|
||||
'0alertmanagerCustomResourceDefinition': import 'alertmanagers-crd.json',
|
||||
'0alertmanagerConfigCustomResourceDefinition': import 'alertmanagerconfigs-crd.json',
|
||||
'0alertmanagerConfigCustomResourceDefinition': (import 'alertmanagerconfigs-crd.json') +
|
||||
if po.config.enableAlertmanagerConfigV1beta1 then
|
||||
(import 'alertmanagerconfigs-v1beta1-crd.libsonnet')
|
||||
else {},
|
||||
'0prometheusCustomResourceDefinition': import 'prometheuses-crd.json',
|
||||
'0servicemonitorCustomResourceDefinition': import 'servicemonitors-crd.json',
|
||||
'0podmonitorCustomResourceDefinition': import 'podmonitors-crd.json',
|
||||
|
|
|
@ -23,15 +23,19 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager"
|
||||
validationv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation/v1alpha1"
|
||||
validationv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation/v1beta1"
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
promoperator "github.com/prometheus-operator/prometheus-operator/pkg/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/conversion"
|
||||
|
||||
v1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
kscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -45,21 +49,24 @@ const (
|
|||
prometheusRuleResource = monitoringv1.PrometheusRuleName
|
||||
prometheusRuleVersion = monitoringv1.Version
|
||||
|
||||
alertManagerConfigResource = monitoringv1alpha1.AlertmanagerConfigName
|
||||
alertManagerConfigCurrentVersion = monitoringv1alpha1.Version
|
||||
alertManagerConfigKind = monitoringv1alpha1.AlertmanagerConfigKind
|
||||
alertManagerConfigResource = monitoringv1beta1.AlertmanagerConfigName
|
||||
alertManagerConfigKind = monitoringv1beta1.AlertmanagerConfigKind
|
||||
|
||||
prometheusRuleValidatePath = "/admission-prometheusrules/validate"
|
||||
prometheusRuleMutatePath = "/admission-prometheusrules/mutate"
|
||||
alertmanagerConfigValidatePath = "/admission-alertmanagerconfigs/validate"
|
||||
convertPath = "/convert"
|
||||
)
|
||||
|
||||
var (
|
||||
deserializer = scheme.Codecs.UniversalDeserializer()
|
||||
deserializer = kscheme.Codecs.UniversalDeserializer()
|
||||
prometheusRuleGVR = metav1.GroupVersionResource{
|
||||
Group: group,
|
||||
Version: prometheusRuleVersion,
|
||||
Resource: prometheusRuleResource,
|
||||
}
|
||||
alertManagerConfigGVR = metav1.GroupVersionResource{
|
||||
alertManagerConfigGR = metav1.GroupResource{
|
||||
Group: group,
|
||||
Version: alertManagerConfigCurrentVersion,
|
||||
Resource: alertManagerConfigResource,
|
||||
}
|
||||
)
|
||||
|
@ -73,16 +80,36 @@ type Admission struct {
|
|||
amConfValidationErrorsCounter prometheus.Counter
|
||||
amConfValidationTriggeredCounter prometheus.Counter
|
||||
logger log.Logger
|
||||
wh *conversion.Webhook
|
||||
}
|
||||
|
||||
func New(logger log.Logger) *Admission {
|
||||
return &Admission{logger: logger}
|
||||
scheme := runtime.NewScheme()
|
||||
|
||||
if err := monitoringv1alpha1.AddToScheme(scheme); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := monitoringv1beta1.AddToScheme(scheme); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
wh := &conversion.Webhook{}
|
||||
if err := wh.InjectScheme(scheme); err != nil {
|
||||
panic(fmt.Sprintf("failed to inject scheme into the webhook handler: %s", err))
|
||||
}
|
||||
|
||||
return &Admission{
|
||||
logger: logger,
|
||||
wh: wh,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Admission) Register(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/admission-prometheusrules/validate", a.servePrometheusRulesValidate)
|
||||
mux.HandleFunc("/admission-prometheusrules/mutate", a.servePrometheusRulesMutate)
|
||||
mux.HandleFunc("/admission-alertmanagerconfigs/validate", a.serveAlertManagerConfigValidate)
|
||||
mux.HandleFunc(prometheusRuleValidatePath, a.servePrometheusRulesValidate)
|
||||
mux.HandleFunc(prometheusRuleMutatePath, a.servePrometheusRulesMutate)
|
||||
mux.HandleFunc(alertmanagerConfigValidatePath, a.serveAlertmanagerConfigValidate)
|
||||
mux.HandleFunc(convertPath, a.serveConvert)
|
||||
}
|
||||
|
||||
func (a *Admission) RegisterMetrics(
|
||||
|
@ -107,8 +134,12 @@ func (a *Admission) servePrometheusRulesValidate(w http.ResponseWriter, r *http.
|
|||
a.serveAdmission(w, r, a.validatePrometheusRules)
|
||||
}
|
||||
|
||||
func (a *Admission) serveAlertManagerConfigValidate(w http.ResponseWriter, r *http.Request) {
|
||||
a.serveAdmission(w, r, a.validateAlertManagerConfig)
|
||||
func (a *Admission) serveAlertmanagerConfigValidate(w http.ResponseWriter, r *http.Request) {
|
||||
a.serveAdmission(w, r, a.validateAlertmanagerConfig)
|
||||
}
|
||||
|
||||
func (a *Admission) serveConvert(w http.ResponseWriter, r *http.Request) {
|
||||
a.wh.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func toAdmissionResponseFailure(message, resource string, errors []error) *v1.AdmissionResponse {
|
||||
|
@ -248,30 +279,51 @@ func (a *Admission) validatePrometheusRules(ar v1.AdmissionReview) *v1.Admission
|
|||
return &v1.AdmissionResponse{Allowed: true}
|
||||
}
|
||||
|
||||
func (a *Admission) validateAlertManagerConfig(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
||||
func (a *Admission) validateAlertmanagerConfig(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
||||
a.incrementCounter(a.amConfValidationTriggeredCounter)
|
||||
level.Debug(a.logger).Log("msg", "Validating alertmanagerconfigs")
|
||||
|
||||
if ar.Request.Resource != alertManagerConfigGVR {
|
||||
gr := metav1.GroupResource{Group: ar.Request.Resource.Group, Resource: ar.Request.Resource.Resource}
|
||||
if gr != alertManagerConfigGR {
|
||||
err := fmt.Errorf("expected resource to be %v, but received %v", alertManagerConfigResource, ar.Request.Resource)
|
||||
level.Warn(a.logger).Log("err", err)
|
||||
a.incrementCounter(a.amConfValidationErrorsCounter)
|
||||
return toAdmissionResponseFailure("Unexpected resource kind", alertManagerConfigResource, []error{err})
|
||||
}
|
||||
|
||||
amConf := &monitoringv1alpha1.AlertmanagerConfig{}
|
||||
var amConf interface{}
|
||||
switch ar.Request.Resource.Version {
|
||||
case monitoringv1alpha1.Version:
|
||||
amConf = &monitoringv1alpha1.AlertmanagerConfig{}
|
||||
case monitoringv1beta1.Version:
|
||||
amConf = &monitoringv1beta1.AlertmanagerConfig{}
|
||||
default:
|
||||
err := fmt.Errorf("expected resource version to be 'v1alpha1' or 'v1beta1', but received %v", ar.Request.Resource.Version)
|
||||
return toAdmissionResponseFailure("Unexpected resource version", alertManagerConfigResource, []error{err})
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(ar.Request.Object.Raw, amConf); err != nil {
|
||||
level.Info(a.logger).Log("msg", errUnmarshalConfig, "err", err)
|
||||
a.incrementCounter(a.amConfValidationErrorsCounter)
|
||||
return toAdmissionResponseFailure(errUnmarshalConfig, alertManagerConfigResource, []error{err})
|
||||
}
|
||||
|
||||
if err := alertmanager.ValidateAlertmanagerConfig(amConf); err != nil {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
switch ar.Request.Resource.Version {
|
||||
case monitoringv1alpha1.Version:
|
||||
err = validationv1alpha1.ValidateAlertmanagerConfig(amConf.(*monitoringv1alpha1.AlertmanagerConfig))
|
||||
case monitoringv1beta1.Version:
|
||||
err = validationv1beta1.ValidateAlertmanagerConfig(amConf.(*monitoringv1beta1.AlertmanagerConfig))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
msg := "invalid config"
|
||||
level.Debug(a.logger).Log("msg", msg, "content", amConf.Spec)
|
||||
level.Debug(a.logger).Log("msg", msg, "content", string(ar.Request.Object.Raw))
|
||||
level.Info(a.logger).Log("msg", msg, "err", err)
|
||||
a.incrementCounter(a.amConfValidationErrorsCounter)
|
||||
return toAdmissionResponseFailure("AlertManagerConfig is invalid", alertManagerConfigResource, []error{err})
|
||||
return toAdmissionResponseFailure("AlertmanagerConfig is invalid", alertManagerConfigResource, []error{err})
|
||||
}
|
||||
return &v1.AdmissionResponse{Allowed: true}
|
||||
}
|
||||
|
|
|
@ -30,13 +30,17 @@ import (
|
|||
"github.com/go-kit/log/level"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
v1 "k8s.io/api/admission/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
)
|
||||
|
||||
func TestMutateRule(t *testing.T) {
|
||||
ts := server(api().servePrometheusRulesMutate)
|
||||
defer ts.Close()
|
||||
|
||||
resp := send(t, ts, goodRulesWithAnnotations)
|
||||
resp := sendAdmissionReview(t, ts, goodRulesWithAnnotations)
|
||||
|
||||
if len(resp.Response.Patch) == 0 {
|
||||
t.Errorf("Expected a patch to be applied but found none")
|
||||
|
@ -47,7 +51,7 @@ func TestMutateRuleNoAnnotations(t *testing.T) {
|
|||
ts := server(api().servePrometheusRulesMutate)
|
||||
defer ts.Close()
|
||||
|
||||
resp := send(t, ts, badRulesNoAnnotations)
|
||||
resp := sendAdmissionReview(t, ts, badRulesNoAnnotations)
|
||||
|
||||
if len(resp.Response.Patch) == 0 {
|
||||
t.Errorf("Expected a patch to be applied but found none")
|
||||
|
@ -58,7 +62,7 @@ func TestAdmitGoodRule(t *testing.T) {
|
|||
ts := server(api().servePrometheusRulesValidate)
|
||||
defer ts.Close()
|
||||
|
||||
resp := send(t, ts, goodRulesWithAnnotations)
|
||||
resp := sendAdmissionReview(t, ts, goodRulesWithAnnotations)
|
||||
|
||||
if !resp.Response.Allowed {
|
||||
t.Errorf("Expected admission to be allowed but it was not")
|
||||
|
@ -69,7 +73,7 @@ func TestAdmitGoodRuleExternalLabels(t *testing.T) {
|
|||
ts := server(api().servePrometheusRulesValidate)
|
||||
defer ts.Close()
|
||||
|
||||
resp := send(t, ts, goodRulesWithExternalLabelsInAnnotations)
|
||||
resp := sendAdmissionReview(t, ts, goodRulesWithExternalLabelsInAnnotations)
|
||||
|
||||
if !resp.Response.Allowed {
|
||||
t.Errorf("Expected admission to be allowed but it was not")
|
||||
|
@ -80,7 +84,7 @@ func TestAdmitBadRule(t *testing.T) {
|
|||
ts := server(api().servePrometheusRulesValidate)
|
||||
defer ts.Close()
|
||||
|
||||
resp := send(t, ts, badRulesNoAnnotations)
|
||||
resp := sendAdmissionReview(t, ts, badRulesNoAnnotations)
|
||||
|
||||
if resp.Response.Allowed {
|
||||
t.Errorf("Expected admission to not be allowed but it was")
|
||||
|
@ -111,7 +115,7 @@ func TestAdmitBadRuleWithBooleanInAnnotations(t *testing.T) {
|
|||
ts := server(api().servePrometheusRulesValidate)
|
||||
defer ts.Close()
|
||||
|
||||
resp := send(t, ts, badRulesWithBooleanInAnnotations)
|
||||
resp := sendAdmissionReview(t, ts, badRulesWithBooleanInAnnotations)
|
||||
|
||||
if resp.Response.Allowed {
|
||||
t.Errorf("Expected admission to not be allowed but it was")
|
||||
|
@ -127,7 +131,7 @@ func TestAdmitBadRuleWithBooleanInAnnotations(t *testing.T) {
|
|||
func TestMutateNonStringsToStrings(t *testing.T) {
|
||||
request := nonStringsInLabelsAnnotations
|
||||
ts := server(api().servePrometheusRulesMutate)
|
||||
resp := send(t, ts, request)
|
||||
resp := sendAdmissionReview(t, ts, request)
|
||||
if len(resp.Response.Patch) == 0 {
|
||||
t.Errorf("Expected a patch to be applied but found none")
|
||||
}
|
||||
|
@ -148,30 +152,32 @@ func TestMutateNonStringsToStrings(t *testing.T) {
|
|||
|
||||
// Sent patched request to validation endpoint
|
||||
ts.Close()
|
||||
ts = server(api().servePrometheusRulesValidate)
|
||||
ts = server(api().servePrometheusRulesMutate)
|
||||
defer ts.Close()
|
||||
|
||||
resp = send(t, ts, request)
|
||||
resp = sendAdmissionReview(t, ts, request)
|
||||
if !resp.Response.Allowed {
|
||||
t.Errorf("Expected admission to be allowed but it was not")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAlertManagerConfigAdmission tests the admission controller
|
||||
// validation of the AlertManagerConfig but does not aim to cover
|
||||
// TestAlertmanagerConfigAdmission tests the admission controller
|
||||
// validation of the AlertmanagerConfig but does not aim to cover
|
||||
// all the edge cases of the Validate function in pkg/alertmanager
|
||||
func TestAlertManagerConfigAdmission(t *testing.T) {
|
||||
ts := server(api().serveAlertManagerConfigValidate)
|
||||
func TestAlertmanagerConfigAdmission(t *testing.T) {
|
||||
ts := server(api().serveAlertmanagerConfigValidate)
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
send string
|
||||
apiVersion string
|
||||
spec string
|
||||
expectAdmissionAllowed bool
|
||||
}{
|
||||
{
|
||||
name: "Test reject on duplicate receiver",
|
||||
send: `{
|
||||
name: "Test reject on duplicate receiver",
|
||||
apiVersion: "v1alpha1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
|
@ -193,8 +199,33 @@ func TestAlertManagerConfigAdmission(t *testing.T) {
|
|||
expectAdmissionAllowed: false,
|
||||
},
|
||||
{
|
||||
name: "Test reject on invalid receiver",
|
||||
send: `{
|
||||
name: "Test reject on duplicate receiver",
|
||||
apiVersion: "v1beta1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
],
|
||||
"groupWait": "30s",
|
||||
"groupInterval": "5m",
|
||||
"repeatInterval": "12h",
|
||||
"receiver": "wechat-example"
|
||||
},
|
||||
"receivers": [
|
||||
{
|
||||
"name": "wechat-example"
|
||||
},
|
||||
{
|
||||
"name": "wechat-example"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expectAdmissionAllowed: false,
|
||||
},
|
||||
{
|
||||
name: "Test reject on invalid receiver",
|
||||
apiVersion: "v1alpha1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
|
@ -223,8 +254,40 @@ func TestAlertManagerConfigAdmission(t *testing.T) {
|
|||
expectAdmissionAllowed: false,
|
||||
},
|
||||
{
|
||||
name: "Test reject on invalid mute time intervals",
|
||||
send: `{
|
||||
name: "Test reject on invalid receiver",
|
||||
apiVersion: "v1beta1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
],
|
||||
"groupWait": "30s",
|
||||
"groupInterval": "5m",
|
||||
"repeatInterval": "12h",
|
||||
"receiver": "wechat-example"
|
||||
},
|
||||
"receivers": [
|
||||
{
|
||||
"name": "wechat-example",
|
||||
"wechatConfigs": [
|
||||
{
|
||||
"apiURL": "https://%<>wechatserver:8080/",
|
||||
"corpID": "wechat-corpid",
|
||||
"apiSecret": {
|
||||
"name": "wechat-config",
|
||||
"key": "apiSecret"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expectAdmissionAllowed: false,
|
||||
},
|
||||
{
|
||||
name: "Test reject on invalid mute time intervals",
|
||||
apiVersion: "v1alpha1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
|
@ -278,8 +341,65 @@ func TestAlertManagerConfigAdmission(t *testing.T) {
|
|||
expectAdmissionAllowed: false,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
send: `{
|
||||
name: "Test reject on invalid time intervals",
|
||||
apiVersion: "v1beta1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
],
|
||||
"groupWait": "30s",
|
||||
"groupInterval": "5m",
|
||||
"repeatInterval": "12h",
|
||||
"receiver": "wechat-example"
|
||||
},
|
||||
"receivers": [
|
||||
{
|
||||
"name": "wechat-example",
|
||||
"wechatConfigs": [
|
||||
{
|
||||
"apiURL": "https://wechatserver:8080",
|
||||
"corpID": "wechat-corpid",
|
||||
"apiSecret": {
|
||||
"name": "wechat-config",
|
||||
"key": "apiSecret"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"timeIntervals": [
|
||||
{
|
||||
"name": "out-of-business-hours",
|
||||
"timeIntervals": [
|
||||
{
|
||||
"weekdays": [
|
||||
"Xaturday",
|
||||
"Sunday"
|
||||
]
|
||||
},
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"startTime": "50:00",
|
||||
"endTime": "08:00"
|
||||
},
|
||||
{
|
||||
"startTime": "18:00",
|
||||
"endTime": "24:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expectAdmissionAllowed: false,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
apiVersion: "v1alpha1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
|
@ -329,14 +449,70 @@ func TestAlertManagerConfigAdmission(t *testing.T) {
|
|||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expectAdmissionAllowed: true,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
apiVersion: "v1beta1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
],
|
||||
"groupWait": "30s",
|
||||
"groupInterval": "5m",
|
||||
"repeatInterval": "12h",
|
||||
"receiver": "wechat-example"
|
||||
},
|
||||
"receivers": [
|
||||
{
|
||||
"name": "wechat-example",
|
||||
"wechatConfigs": [
|
||||
{
|
||||
"apiURL": "http://wechatserver:8080/",
|
||||
"corpID": "wechat-corpid",
|
||||
"apiSecret": {
|
||||
"name": "wechat-config",
|
||||
"key": "apiSecret"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"timeIntervals": [
|
||||
{
|
||||
"name": "out-of-business-hours",
|
||||
"timeIntervals": [
|
||||
{
|
||||
"weekdays": [
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
]
|
||||
},
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"startTime": "00:00",
|
||||
"endTime": "08:00"
|
||||
},
|
||||
{
|
||||
"startTime": "18:00",
|
||||
"endTime": "24:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
expectAdmissionAllowed: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
resp := send(t, ts, buildAlertManagerConfigFromSpec(t, tc.send))
|
||||
t.Run(tc.name+","+tc.apiVersion, func(t *testing.T) {
|
||||
resp := sendAdmissionReview(t, ts, buildAdmissionReviewFromAlertmanagerConfigSpec(t, tc.apiVersion, tc.spec))
|
||||
if resp.Response.Allowed != tc.expectAdmissionAllowed {
|
||||
t.Errorf(
|
||||
"Unexpected admission result, wanted %v but got %v - (warnings=%v) - (details=%v)",
|
||||
|
@ -346,6 +522,194 @@ func TestAlertManagerConfigAdmission(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAlertmanagerConfigConversion(t *testing.T) {
|
||||
ts := server(api().serveConvert)
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
from string
|
||||
to string
|
||||
spec string
|
||||
|
||||
checkFn func(converted []byte) error
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
from: "v1alpha1",
|
||||
to: "v1beta1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
],
|
||||
"groupWait": "30s",
|
||||
"groupInterval": "5m",
|
||||
"repeatInterval": "12h",
|
||||
"receiver": "wechat-example"
|
||||
},
|
||||
"receivers": [
|
||||
{
|
||||
"name": "wechat-example",
|
||||
"wechatConfigs": [
|
||||
{
|
||||
"apiURL": "http://wechatserver:8080/",
|
||||
"corpID": "wechat-corpid",
|
||||
"apiSecret": {
|
||||
"name": "wechat-config",
|
||||
"key": "apiSecret"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"muteTimeIntervals": [
|
||||
{
|
||||
"name": "out-of-business-hours",
|
||||
"timeIntervals": [
|
||||
{
|
||||
"weekdays": [
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
]
|
||||
},
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"startTime": "00:00",
|
||||
"endTime": "08:00"
|
||||
},
|
||||
{
|
||||
"startTime": "18:00",
|
||||
"endTime": "24:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
|
||||
checkFn: func(converted []byte) error {
|
||||
o := v1beta1.AlertmanagerConfig{}
|
||||
|
||||
err := json.Unmarshal(converted, &o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(o.Spec.TimeIntervals) != 1 {
|
||||
return fmt.Errorf("expecting 1 item in spec.timeIntervals, got %d", len(o.Spec.TimeIntervals))
|
||||
}
|
||||
|
||||
if o.Spec.TimeIntervals[0].Name != "out-of-business-hours" {
|
||||
return fmt.Errorf("expecting spec.timeIntervals[0].name to be %q, got %q", "out-of-business-hours", o.Spec.TimeIntervals[0].Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path",
|
||||
from: "v1beta1",
|
||||
to: "v1alpha1",
|
||||
spec: `{
|
||||
"route": {
|
||||
"groupBy": [
|
||||
"job"
|
||||
],
|
||||
"groupWait": "30s",
|
||||
"groupInterval": "5m",
|
||||
"repeatInterval": "12h",
|
||||
"receiver": "wechat-example"
|
||||
},
|
||||
"receivers": [
|
||||
{
|
||||
"name": "wechat-example",
|
||||
"wechatConfigs": [
|
||||
{
|
||||
"apiURL": "http://wechatserver:8080/",
|
||||
"corpID": "wechat-corpid",
|
||||
"apiSecret": {
|
||||
"name": "wechat-config",
|
||||
"key": "apiSecret"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"timeIntervals": [
|
||||
{
|
||||
"name": "out-of-business-hours",
|
||||
"timeIntervals": [
|
||||
{
|
||||
"weekdays": [
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
]
|
||||
},
|
||||
{
|
||||
"times": [
|
||||
{
|
||||
"startTime": "00:00",
|
||||
"endTime": "08:00"
|
||||
},
|
||||
{
|
||||
"startTime": "18:00",
|
||||
"endTime": "24:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
|
||||
checkFn: func(converted []byte) error {
|
||||
o := v1alpha1.AlertmanagerConfig{}
|
||||
|
||||
err := json.Unmarshal(converted, &o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(o.Spec.MuteTimeIntervals) != 1 {
|
||||
return fmt.Errorf("expecting 1 item in spec.muteTimeIntervals, got %d", len(o.Spec.MuteTimeIntervals))
|
||||
}
|
||||
|
||||
if o.Spec.MuteTimeIntervals[0].Name != "out-of-business-hours" {
|
||||
return fmt.Errorf("expecting spec.muteTimeIntervals[0].name to be %q, got %q", "out-of-business-hours", o.Spec.MuteTimeIntervals[0].Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name+","+tc.from+">"+tc.to, func(t *testing.T) {
|
||||
resp := sendConversionReview(t, ts, buildConversionReviewFromAlertmanagerConfigSpec(t, tc.from, tc.to, tc.spec))
|
||||
if resp.Response.Result.Status != "Success" {
|
||||
t.Fatalf(
|
||||
"Unexpected conversion result, wanted 'Success' but got %v - (result=%v)",
|
||||
resp.Response.Result.Status,
|
||||
resp.Response.Result)
|
||||
}
|
||||
|
||||
if len(resp.Response.ConvertedObjects) != 1 {
|
||||
t.Fatalf("expected 1 converted object, got %d", len(resp.Response.ConvertedObjects))
|
||||
}
|
||||
|
||||
if tc.checkFn == nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := tc.checkFn(resp.Response.ConvertedObjects[0].Raw)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error while checking converted object: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func api() *Admission {
|
||||
validationTriggered := prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Name: "prometheus_operator_rule_validation_triggered_total",
|
||||
|
@ -368,29 +732,48 @@ func api() *Admission {
|
|||
|
||||
a := New(level.NewFilter(log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout)), level.AllowNone()))
|
||||
a.RegisterMetrics(validationTriggered, validationErrors, alertManagerConfigValidationTriggered, alertManagerConfigValidationError)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
type serveFunc func(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
func server(s serveFunc) *httptest.Server {
|
||||
return httptest.NewServer(http.HandlerFunc(s))
|
||||
func server(h http.HandlerFunc) *httptest.Server {
|
||||
return httptest.NewServer(h)
|
||||
}
|
||||
|
||||
func send(t *testing.T, ts *httptest.Server, rules []byte) *v1.AdmissionReview {
|
||||
resp, err := http.Post(ts.URL, "application/json", bytes.NewReader(rules))
|
||||
func sendAdmissionReview(t *testing.T, ts *httptest.Server, b []byte) *v1.AdmissionReview {
|
||||
resp, err := http.Post(ts.URL, "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
t.Errorf("Publish() returned an error: %s", err)
|
||||
t.Fatalf("POST request returned an error: %s", err)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("ioutil.ReadAll(resp.Body) returned an error: %s", err)
|
||||
t.Fatalf("ioutil.ReadAll(resp.Body) returned an error: %s", err)
|
||||
}
|
||||
|
||||
rev := &v1.AdmissionReview{}
|
||||
if err := json.Unmarshal(body, rev); err != nil {
|
||||
t.Errorf("unable to parse webhook response: %s", err)
|
||||
t.Fatalf("unable to parse webhook response: %s", err)
|
||||
}
|
||||
|
||||
return rev
|
||||
}
|
||||
|
||||
func sendConversionReview(t *testing.T, ts *httptest.Server, b []byte) *apiextensionsv1.ConversionReview {
|
||||
t.Helper()
|
||||
resp, err := http.Post(ts.URL, "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
t.Fatalf("POST request returned an error: %s", err)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("ioutil.ReadAll(resp.Body) returned an error: %s", err)
|
||||
}
|
||||
|
||||
rev := &apiextensionsv1.ConversionReview{}
|
||||
if err := json.Unmarshal(body, rev); err != nil {
|
||||
t.Fatalf("unable to parse webhook response: %s (%q)", err, string(body))
|
||||
}
|
||||
|
||||
return rev
|
||||
|
@ -731,7 +1114,7 @@ var nonStringsInLabelsAnnotations = []byte(`
|
|||
}
|
||||
}`)
|
||||
|
||||
func buildAlertManagerConfigFromSpec(t *testing.T, spec string) []byte {
|
||||
func buildAdmissionReviewFromAlertmanagerConfigSpec(t *testing.T, version, spec string) []byte {
|
||||
t.Helper()
|
||||
tmpl := fmt.Sprintf(`
|
||||
{
|
||||
|
@ -776,11 +1159,42 @@ func buildAlertManagerConfigFromSpec(t *testing.T, spec string) []byte {
|
|||
}
|
||||
`,
|
||||
group,
|
||||
alertManagerConfigCurrentVersion,
|
||||
version,
|
||||
alertManagerConfigKind,
|
||||
alertManagerConfigCurrentVersion,
|
||||
version,
|
||||
alertManagerConfigResource,
|
||||
alertManagerConfigCurrentVersion,
|
||||
version,
|
||||
alertManagerConfigKind,
|
||||
spec)
|
||||
return []byte(tmpl)
|
||||
}
|
||||
|
||||
func buildConversionReviewFromAlertmanagerConfigSpec(t *testing.T, from, to, spec string) []byte {
|
||||
t.Helper()
|
||||
tmpl := fmt.Sprintf(`
|
||||
{
|
||||
"kind": "ConversionReview",
|
||||
"apiVersion": "apiextensions.k8s.io/v1",
|
||||
"request": {
|
||||
"uid": "87c5df7f-5090-11e9-b9b4-02425473f309",
|
||||
"desiredAPIVersion": "monitoring.coreos.com/%s",
|
||||
"objects": [{
|
||||
"apiVersion": "monitoring.coreos.com/%s",
|
||||
"kind": "%s",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-03-27T13:02:09Z",
|
||||
"generation": 1,
|
||||
"name": "test",
|
||||
"namespace": "monitoring",
|
||||
"uid": "87c5d31d-5090-11e9-b9b4-02425473f309"
|
||||
},
|
||||
"spec": %s
|
||||
}]
|
||||
}
|
||||
}
|
||||
`,
|
||||
to,
|
||||
from,
|
||||
alertManagerConfigKind,
|
||||
spec)
|
||||
return []byte(tmpl)
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation"
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/assets"
|
||||
|
@ -318,7 +319,7 @@ func (cb *configBuilder) getValidURLFromSecret(ctx context.Context, namespace st
|
|||
}
|
||||
|
||||
url = strings.TrimSpace(url)
|
||||
if _, err := ValidateURL(url); err != nil {
|
||||
if _, err := validation.ValidateURL(url); err != nil {
|
||||
return url, errors.Wrapf(err, "invalid URL %q in key %q from secret %q", url, selector.Key, selector.Name)
|
||||
}
|
||||
return url, nil
|
||||
|
@ -534,7 +535,7 @@ func (cb *configBuilder) convertWebhookConfig(ctx context.Context, in monitoring
|
|||
}
|
||||
out.URL = url
|
||||
} else if in.URL != nil {
|
||||
url, err := ValidateURL(*in.URL)
|
||||
url, err := validation.ValidateURL(*in.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation"
|
||||
validationv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation/v1alpha1"
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/assets"
|
||||
|
@ -904,7 +906,7 @@ func (c *Operator) loadConfigurationFromSecret(ctx context.Context, am *monitori
|
|||
func (c *Operator) provisionAlertmanagerConfiguration(ctx context.Context, am *monitoringv1.Alertmanager, store *assets.Store) error {
|
||||
namespacedLogger := log.With(c.logger, "alertmanager", am.Name, "namespace", am.Namespace)
|
||||
|
||||
if err := ValidateAlertmanager(am); err != nil {
|
||||
if err := validation.ValidateAlertmanager(am); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1111,7 +1113,7 @@ func (c *Operator) selectAlertmanagerConfigs(ctx context.Context, am *monitoring
|
|||
// checkAlertmanagerConfigResource verifies that an AlertmanagerConfig object is valid
|
||||
// for the given Alertmanager version and has no missing references to other objects.
|
||||
func checkAlertmanagerConfigResource(ctx context.Context, amc *monitoringv1alpha1.AlertmanagerConfig, amVersion semver.Version, store *assets.Store) error {
|
||||
if err := ValidateAlertmanagerConfig(amc); err != nil {
|
||||
if err := validationv1alpha1.ValidateAlertmanagerConfig(amc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1353,7 +1355,7 @@ func checkWebhookConfigs(
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := ValidateURL(strings.TrimSpace(url)); err != nil {
|
||||
if _, err := validation.ValidateURL(strings.TrimSpace(url)); err != nil {
|
||||
return errors.Wrapf(err, "webhook 'url' %s invalid", url)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,9 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package alertmanager
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
|
@ -23,44 +22,12 @@ import (
|
|||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/operator"
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
)
|
||||
|
||||
var durationRe = regexp.MustCompile(`^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$`)
|
||||
|
||||
// ValidateAlertmanager runs extra validation on the AlertManager fields which
|
||||
// can't be done at the CRD schema validation level.
|
||||
func ValidateAlertmanager(am *monitoringv1.Alertmanager) error {
|
||||
if am.Spec.Retention != "" {
|
||||
if err := operator.ValidateDurationField(am.Spec.Retention); err != nil {
|
||||
return errors.Wrap(err, "invalid retention value specified")
|
||||
}
|
||||
}
|
||||
|
||||
if am.Spec.ClusterGossipInterval != "" {
|
||||
if err := operator.ValidateDurationField(am.Spec.ClusterGossipInterval); err != nil {
|
||||
return errors.Wrap(err, "invalid clusterGossipInterval value specified")
|
||||
}
|
||||
}
|
||||
|
||||
if am.Spec.ClusterPushpullInterval != "" {
|
||||
if err := operator.ValidateDurationField(am.Spec.ClusterPushpullInterval); err != nil {
|
||||
return errors.Wrap(err, "invalid clusterPushpullInterval value specified")
|
||||
}
|
||||
}
|
||||
|
||||
if am.Spec.ClusterPeerTimeout != "" {
|
||||
if err := operator.ValidateDurationField(am.Spec.ClusterPeerTimeout); err != nil {
|
||||
return errors.Wrap(err, "invalid clusterPeerTimeout value specified")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateAlertmanagerConfig checks that the given resource complies with the
|
||||
// semantics of the Alertmanager configuration.
|
||||
// In particular, it verifies things that can't be modelized with the OpenAPI
|
||||
|
@ -79,19 +46,6 @@ func ValidateAlertmanagerConfig(amc *monitoringv1alpha1.AlertmanagerConfig) erro
|
|||
return validateAlertManagerRoutes(amc.Spec.Route, receivers, muteTimeIntervals, true)
|
||||
}
|
||||
|
||||
// ValidateURL against the config.URL
|
||||
// This could potentially become a regex and be validated via OpenAPI
|
||||
// but right now, since we know we need to unmarshal into an upstream type
|
||||
// after conversion, we validate we don't error when doing so
|
||||
func ValidateURL(url string) (*config.URL, error) {
|
||||
var u config.URL
|
||||
err := json.Unmarshal([]byte(fmt.Sprintf(`"%s"`, url)), &u)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("validate url from string failed for %s: %w", url, err)
|
||||
}
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
func validateReceivers(receivers []monitoringv1alpha1.Receiver) (map[string]struct{}, error) {
|
||||
var err error
|
||||
receiverNames := make(map[string]struct{})
|
||||
|
@ -150,7 +104,7 @@ func validateReceivers(receivers []monitoringv1alpha1.Receiver) (map[string]stru
|
|||
func validatePagerDutyConfigs(configs []monitoringv1alpha1.PagerDutyConfig) error {
|
||||
for _, conf := range configs {
|
||||
if conf.URL != "" {
|
||||
if _, err := ValidateURL(conf.URL); err != nil {
|
||||
if _, err := validation.ValidateURL(conf.URL); err != nil {
|
||||
return errors.Wrap(err, "pagerduty validation failed for 'url'")
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +125,7 @@ func validateOpsGenieConfigs(configs []monitoringv1alpha1.OpsGenieConfig) error
|
|||
return err
|
||||
}
|
||||
if config.APIURL != "" {
|
||||
if _, err := ValidateURL(config.APIURL); err != nil {
|
||||
if _, err := validation.ValidateURL(config.APIURL); err != nil {
|
||||
return errors.Wrap(err, "invalid 'apiURL'")
|
||||
}
|
||||
}
|
||||
|
@ -202,7 +156,7 @@ func validateWebhookConfigs(configs []monitoringv1alpha1.WebhookConfig) error {
|
|||
return errors.New("one of 'url' or 'urlSecret' must be specified")
|
||||
}
|
||||
if config.URL != nil {
|
||||
if _, err := ValidateURL(*config.URL); err != nil {
|
||||
if _, err := validation.ValidateURL(*config.URL); err != nil {
|
||||
return errors.Wrapf(err, "invalid 'url'")
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +171,7 @@ func validateWebhookConfigs(configs []monitoringv1alpha1.WebhookConfig) error {
|
|||
func validateWechatConfigs(configs []monitoringv1alpha1.WeChatConfig) error {
|
||||
for _, config := range configs {
|
||||
if config.APIURL != "" {
|
||||
if _, err := ValidateURL(config.APIURL); err != nil {
|
||||
if _, err := validation.ValidateURL(config.APIURL); err != nil {
|
||||
return errors.Wrap(err, "invalid 'apiURL'")
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +238,7 @@ func validateVictorOpsConfigs(configs []monitoringv1alpha1.VictorOpsConfig) erro
|
|||
}
|
||||
|
||||
if config.APIURL != "" {
|
||||
if _, err := ValidateURL(config.APIURL); err != nil {
|
||||
if _, err := validation.ValidateURL(config.APIURL); err != nil {
|
||||
return errors.Wrapf(err, "'apiURL' %s invalid", config.APIURL)
|
||||
}
|
||||
}
|
353
pkg/alertmanager/validation/v1beta1/validation.go
Normal file
353
pkg/alertmanager/validation/v1beta1/validation.go
Normal file
|
@ -0,0 +1,353 @@
|
|||
// Copyright 2021 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager/validation"
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
)
|
||||
|
||||
var durationRe = regexp.MustCompile(`^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$`)
|
||||
|
||||
// ValidateAlertmanagerConfig checks that the given resource complies with the
|
||||
// semantics of the Alertmanager configuration.
|
||||
// In particular, it verifies things that can't be modelized with the OpenAPI
|
||||
// specification such as routes should refer to an existing receiver.
|
||||
func ValidateAlertmanagerConfig(amc *monitoringv1beta1.AlertmanagerConfig) error {
|
||||
receivers, err := validateReceivers(amc.Spec.Receivers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timeIntervals, err := validateTimeIntervals(amc.Spec.TimeIntervals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validateAlertManagerRoutes(amc.Spec.Route, receivers, timeIntervals, true)
|
||||
}
|
||||
|
||||
func validateReceivers(receivers []monitoringv1beta1.Receiver) (map[string]struct{}, error) {
|
||||
var err error
|
||||
receiverNames := make(map[string]struct{})
|
||||
|
||||
for _, receiver := range receivers {
|
||||
if _, found := receiverNames[receiver.Name]; found {
|
||||
return nil, errors.Errorf("%q receiver is not unique", receiver.Name)
|
||||
}
|
||||
receiverNames[receiver.Name] = struct{}{}
|
||||
|
||||
if err = validatePagerDutyConfigs(receiver.PagerDutyConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'pagerDutyConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
|
||||
if err := validateOpsGenieConfigs(receiver.OpsGenieConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'opsGenieConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
|
||||
if err := validateSlackConfigs(receiver.SlackConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'slackConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
|
||||
if err := validateWebhookConfigs(receiver.WebhookConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'webhookConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
|
||||
if err := validateWechatConfigs(receiver.WeChatConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'weChatConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
|
||||
if err := validateEmailConfig(receiver.EmailConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'emailConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
|
||||
if err := validateVictorOpsConfigs(receiver.VictorOpsConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'victorOpsConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
|
||||
if err := validatePushoverConfigs(receiver.PushoverConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'pushOverConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
|
||||
if err := validateSnsConfigs(receiver.SNSConfigs); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to validate 'snsConfig' - receiver %s", receiver.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return receiverNames, nil
|
||||
}
|
||||
|
||||
func validatePagerDutyConfigs(configs []monitoringv1beta1.PagerDutyConfig) error {
|
||||
for _, conf := range configs {
|
||||
if conf.URL != "" {
|
||||
if _, err := validation.ValidateURL(conf.URL); err != nil {
|
||||
return errors.Wrap(err, "pagerduty validation failed for 'url'")
|
||||
}
|
||||
}
|
||||
if conf.RoutingKey == nil && conf.ServiceKey == nil {
|
||||
return errors.New("one of 'routingKey' or 'serviceKey' is required")
|
||||
}
|
||||
|
||||
if err := conf.HTTPConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateOpsGenieConfigs(configs []monitoringv1beta1.OpsGenieConfig) error {
|
||||
for _, config := range configs {
|
||||
if err := config.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if config.APIURL != "" {
|
||||
if _, err := validation.ValidateURL(config.APIURL); err != nil {
|
||||
return errors.Wrap(err, "invalid 'apiURL'")
|
||||
}
|
||||
}
|
||||
|
||||
if err := config.HTTPConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateSlackConfigs(configs []monitoringv1beta1.SlackConfig) error {
|
||||
for _, config := range configs {
|
||||
if err := config.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := config.HTTPConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateWebhookConfigs(configs []monitoringv1beta1.WebhookConfig) error {
|
||||
for _, config := range configs {
|
||||
if config.URL == nil && config.URLSecret == nil {
|
||||
return errors.New("one of 'url' or 'urlSecret' must be specified")
|
||||
}
|
||||
if config.URL != nil {
|
||||
if _, err := validation.ValidateURL(*config.URL); err != nil {
|
||||
return errors.Wrapf(err, "invalid 'url'")
|
||||
}
|
||||
}
|
||||
|
||||
if err := config.HTTPConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateWechatConfigs(configs []monitoringv1beta1.WeChatConfig) error {
|
||||
for _, config := range configs {
|
||||
if config.APIURL != "" {
|
||||
if _, err := validation.ValidateURL(config.APIURL); err != nil {
|
||||
return errors.Wrap(err, "invalid 'apiURL'")
|
||||
}
|
||||
}
|
||||
|
||||
if err := config.HTTPConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateEmailConfig(configs []monitoringv1beta1.EmailConfig) error {
|
||||
for _, config := range configs {
|
||||
if config.To == "" {
|
||||
return errors.New("missing 'to' address")
|
||||
}
|
||||
|
||||
if config.Smarthost != "" {
|
||||
_, _, err := net.SplitHostPort(config.Smarthost)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "invalid field 'smarthost': %s", config.Smarthost)
|
||||
}
|
||||
}
|
||||
|
||||
if config.Headers != nil {
|
||||
// Header names are case-insensitive, check for collisions.
|
||||
normalizedHeaders := map[string]struct{}{}
|
||||
for _, v := range config.Headers {
|
||||
normalized := strings.Title(v.Key)
|
||||
if _, ok := normalizedHeaders[normalized]; ok {
|
||||
return fmt.Errorf("duplicate header %q", normalized)
|
||||
}
|
||||
normalizedHeaders[normalized] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateVictorOpsConfigs(configs []monitoringv1beta1.VictorOpsConfig) error {
|
||||
for _, config := range configs {
|
||||
|
||||
// from https://github.com/prometheus/alertmanager/blob/a7f9fdadbecbb7e692d2cd8d3334e3d6de1602e1/config/notifiers.go#L497
|
||||
reservedFields := map[string]struct{}{
|
||||
"routing_key": {},
|
||||
"message_type": {},
|
||||
"state_message": {},
|
||||
"entity_display_name": {},
|
||||
"monitoring_tool": {},
|
||||
"entity_id": {},
|
||||
"entity_state": {},
|
||||
}
|
||||
|
||||
if len(config.CustomFields) > 0 {
|
||||
for _, v := range config.CustomFields {
|
||||
if _, ok := reservedFields[v.Key]; ok {
|
||||
return fmt.Errorf("usage of reserved word %q is not allowed in custom fields", v.Key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if config.RoutingKey == "" {
|
||||
return errors.New("missing 'routingKey' key")
|
||||
}
|
||||
|
||||
if config.APIURL != "" {
|
||||
if _, err := validation.ValidateURL(config.APIURL); err != nil {
|
||||
return errors.Wrapf(err, "'apiURL' %s invalid", config.APIURL)
|
||||
}
|
||||
}
|
||||
|
||||
if err := config.HTTPConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePushoverConfigs(configs []monitoringv1beta1.PushoverConfig) error {
|
||||
for _, config := range configs {
|
||||
if config.UserKey == nil {
|
||||
return errors.Errorf("mandatory field %q is empty", "userKey")
|
||||
}
|
||||
|
||||
if config.Token == nil {
|
||||
return errors.Errorf("mandatory field %q is empty", "token")
|
||||
}
|
||||
|
||||
if err := config.HTTPConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateSnsConfigs(configs []monitoringv1beta1.SNSConfig) error {
|
||||
for _, config := range configs {
|
||||
if (config.TargetARN == "") != (config.TopicARN == "") != (config.PhoneNumber == "") {
|
||||
return fmt.Errorf("must provide either a Target ARN, Topic ARN, or Phone Number for SNS config")
|
||||
}
|
||||
|
||||
if err := config.HTTPConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateAlertManagerRoutes verifies that the given route and all its children are semantically valid.
|
||||
// because of the self-referential issues mentioned in https://github.com/kubernetes/kubernetes/issues/62872
|
||||
// it is not currently possible to apply OpenAPI validation to a v1beta1.Route
|
||||
func validateAlertManagerRoutes(r *monitoringv1beta1.Route, receivers, timeIntervals map[string]struct{}, topLevelRoute bool) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.Receiver == "" {
|
||||
if topLevelRoute {
|
||||
return errors.Errorf("root route must define a receiver")
|
||||
}
|
||||
} else {
|
||||
if _, found := receivers[r.Receiver]; !found {
|
||||
return errors.Errorf("receiver %q not found", r.Receiver)
|
||||
}
|
||||
}
|
||||
|
||||
if groupLen := len(r.GroupBy); groupLen > 0 {
|
||||
groupedBy := make(map[string]struct{}, groupLen)
|
||||
for _, str := range r.GroupBy {
|
||||
if _, found := groupedBy[str]; found {
|
||||
return errors.Errorf("duplicate values not permitted in route 'groupBy': %v", r.GroupBy)
|
||||
}
|
||||
groupedBy[str] = struct{}{}
|
||||
}
|
||||
if _, found := groupedBy["..."]; found && groupLen > 1 {
|
||||
return errors.Errorf("'...' must be a sole value in route 'groupBy': %v", r.GroupBy)
|
||||
}
|
||||
}
|
||||
|
||||
for _, namedTimeInterval := range r.MuteTimeIntervals {
|
||||
if _, found := timeIntervals[namedTimeInterval]; !found {
|
||||
return errors.Errorf("time interval %q not found", namedTimeInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// validate that if defaults are set, they match regex
|
||||
if r.GroupInterval != "" && !durationRe.MatchString(r.GroupInterval) {
|
||||
return errors.Errorf("groupInterval %s does not match required regex: %s", r.GroupInterval, durationRe.String())
|
||||
|
||||
}
|
||||
if r.GroupWait != "" && !durationRe.MatchString(r.GroupWait) {
|
||||
return errors.Errorf("groupWait %s does not match required regex: %s", r.GroupWait, durationRe.String())
|
||||
}
|
||||
|
||||
if r.RepeatInterval != "" && !durationRe.MatchString(r.RepeatInterval) {
|
||||
return errors.Errorf("repeatInterval %s does not match required regex: %s", r.RepeatInterval, durationRe.String())
|
||||
}
|
||||
|
||||
children, err := r.ChildRoutes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range children {
|
||||
if err := validateAlertManagerRoutes(&children[i], receivers, timeIntervals, false); err != nil {
|
||||
return errors.Wrapf(err, "route[%d]", i)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateTimeIntervals(timeIntervals []monitoringv1beta1.TimeInterval) (map[string]struct{}, error) {
|
||||
timeIntervalNames := make(map[string]struct{}, len(timeIntervals))
|
||||
|
||||
for i, ti := range timeIntervals {
|
||||
if err := ti.Validate(); err != nil {
|
||||
return nil, errors.Wrapf(err, "time interval[%d] is invalid", i)
|
||||
}
|
||||
timeIntervalNames[ti.Name] = struct{}{}
|
||||
}
|
||||
return timeIntervalNames, nil
|
||||
}
|
|
@ -12,30 +12,25 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package alertmanager
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
)
|
||||
|
||||
func TestValidateAlertmanagerConfig(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
in *monitoringv1alpha1.AlertmanagerConfig
|
||||
in *monitoringv1beta1.AlertmanagerConfig
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test fail to validate on duplicate receiver",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
|
@ -49,17 +44,17 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate on opsgenie config - missing required fields",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
OpsGenieConfigs: []monitoringv1alpha1.OpsGenieConfig{
|
||||
OpsGenieConfigs: []monitoringv1beta1.OpsGenieConfig{
|
||||
{
|
||||
Responders: []monitoringv1alpha1.OpsGenieConfigResponder{
|
||||
Responders: []monitoringv1beta1.OpsGenieConfigResponder{
|
||||
{},
|
||||
},
|
||||
},
|
||||
|
@ -72,28 +67,28 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate on slack config - valid action fields - invalid fields field",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
SlackConfigs: []monitoringv1alpha1.SlackConfig{
|
||||
SlackConfigs: []monitoringv1beta1.SlackConfig{
|
||||
{
|
||||
Actions: []monitoringv1alpha1.SlackAction{
|
||||
Actions: []monitoringv1beta1.SlackAction{
|
||||
{
|
||||
Type: "a",
|
||||
Text: "b",
|
||||
URL: "www.test.com",
|
||||
Name: "c",
|
||||
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
|
||||
ConfirmField: &monitoringv1beta1.SlackConfirmationField{
|
||||
Text: "d",
|
||||
},
|
||||
},
|
||||
},
|
||||
Fields: []monitoringv1alpha1.SlackField{
|
||||
Fields: []monitoringv1beta1.SlackField{
|
||||
{},
|
||||
},
|
||||
},
|
||||
|
@ -106,15 +101,15 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate webhook config - missing required fields",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
|
||||
WebhookConfigs: []monitoringv1beta1.WebhookConfig{
|
||||
{},
|
||||
},
|
||||
},
|
||||
|
@ -125,15 +120,15 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate wechat config - invalid URL",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
WeChatConfigs: []monitoringv1alpha1.WeChatConfig{
|
||||
WeChatConfigs: []monitoringv1beta1.WeChatConfig{
|
||||
{
|
||||
APIURL: "http://%><invalid.com",
|
||||
},
|
||||
|
@ -146,15 +141,15 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate email config - missing to field",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
EmailConfigs: []monitoringv1alpha1.EmailConfig{
|
||||
EmailConfigs: []monitoringv1beta1.EmailConfig{
|
||||
{},
|
||||
},
|
||||
},
|
||||
|
@ -165,15 +160,15 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate email config - invalid smarthost",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
EmailConfigs: []monitoringv1alpha1.EmailConfig{
|
||||
EmailConfigs: []monitoringv1beta1.EmailConfig{
|
||||
{
|
||||
To: "a",
|
||||
Smarthost: "invalid",
|
||||
|
@ -187,15 +182,15 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate VictorOpsConfigs - missing routing key",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
VictorOpsConfigs: []monitoringv1alpha1.VictorOpsConfig{
|
||||
VictorOpsConfigs: []monitoringv1beta1.VictorOpsConfig{
|
||||
{},
|
||||
},
|
||||
},
|
||||
|
@ -206,18 +201,18 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate VictorOpsConfigs - reservedFields",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
VictorOpsConfigs: []monitoringv1alpha1.VictorOpsConfig{
|
||||
VictorOpsConfigs: []monitoringv1beta1.VictorOpsConfig{
|
||||
{
|
||||
RoutingKey: "a",
|
||||
CustomFields: []monitoringv1alpha1.KeyValue{
|
||||
CustomFields: []monitoringv1beta1.KeyValue{
|
||||
{
|
||||
Key: "routing_key",
|
||||
Value: "routing_key",
|
||||
|
@ -233,15 +228,15 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate PushoverConfigs - missing user key",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
PushoverConfigs: []monitoringv1alpha1.PushoverConfig{
|
||||
PushoverConfigs: []monitoringv1beta1.PushoverConfig{
|
||||
{},
|
||||
},
|
||||
},
|
||||
|
@ -252,17 +247,20 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate PushoverConfigs - missing token",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
PushoverConfigs: []monitoringv1alpha1.PushoverConfig{
|
||||
PushoverConfigs: []monitoringv1beta1.PushoverConfig{
|
||||
{
|
||||
UserKey: &v1.SecretKeySelector{},
|
||||
UserKey: &monitoringv1beta1.SecretKeySelector{
|
||||
Name: "creds",
|
||||
Key: "user",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -273,14 +271,14 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate routes - parent route has no receiver",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
},
|
||||
Route: &monitoringv1alpha1.Route{
|
||||
Route: &monitoringv1beta1.Route{
|
||||
Receiver: "will-not-be-found",
|
||||
},
|
||||
},
|
||||
|
@ -289,14 +287,14 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate routes with duplicate groupBy",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
},
|
||||
Route: &monitoringv1alpha1.Route{
|
||||
Route: &monitoringv1beta1.Route{
|
||||
Receiver: "same",
|
||||
GroupBy: []string{"job", "job"},
|
||||
},
|
||||
|
@ -306,14 +304,14 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate routes with exclusive value and other in groupBy",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
},
|
||||
Route: &monitoringv1alpha1.Route{
|
||||
Route: &monitoringv1beta1.Route{
|
||||
Receiver: "same",
|
||||
GroupBy: []string{"job", "..."},
|
||||
},
|
||||
|
@ -323,14 +321,14 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test fail to validate routes - named mute time interval does not exist",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
},
|
||||
Route: &monitoringv1alpha1.Route{
|
||||
Route: &monitoringv1beta1.Route{
|
||||
Receiver: "same",
|
||||
MuteTimeIntervals: []string{"awol"},
|
||||
},
|
||||
|
@ -340,17 +338,17 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
in: &monitoringv1alpha1.AlertmanagerConfig{
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1alpha1.Receiver{
|
||||
in: &monitoringv1beta1.AlertmanagerConfig{
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Receivers: []monitoringv1beta1.Receiver{
|
||||
{
|
||||
Name: "same",
|
||||
},
|
||||
{
|
||||
Name: "different",
|
||||
OpsGenieConfigs: []monitoringv1alpha1.OpsGenieConfig{
|
||||
OpsGenieConfigs: []monitoringv1beta1.OpsGenieConfig{
|
||||
{
|
||||
Responders: []monitoringv1alpha1.OpsGenieConfigResponder{
|
||||
Responders: []monitoringv1beta1.OpsGenieConfigResponder{
|
||||
{
|
||||
ID: "a",
|
||||
Name: "b",
|
||||
|
@ -359,20 +357,20 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
SlackConfigs: []monitoringv1alpha1.SlackConfig{
|
||||
SlackConfigs: []monitoringv1beta1.SlackConfig{
|
||||
{
|
||||
Actions: []monitoringv1alpha1.SlackAction{
|
||||
Actions: []monitoringv1beta1.SlackAction{
|
||||
{
|
||||
Type: "a",
|
||||
Text: "b",
|
||||
URL: "https://www.test.com",
|
||||
Name: "c",
|
||||
ConfirmField: &monitoringv1alpha1.SlackConfirmationField{
|
||||
ConfirmField: &monitoringv1beta1.SlackConfirmationField{
|
||||
Text: "d",
|
||||
},
|
||||
},
|
||||
},
|
||||
Fields: []monitoringv1alpha1.SlackField{
|
||||
Fields: []monitoringv1beta1.SlackField{
|
||||
{
|
||||
Title: "a",
|
||||
Value: "b",
|
||||
|
@ -380,22 +378,25 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
WebhookConfigs: []monitoringv1alpha1.WebhookConfig{
|
||||
WebhookConfigs: []monitoringv1beta1.WebhookConfig{
|
||||
{
|
||||
URL: strToPtr("https://www.test.com"),
|
||||
URLSecret: &v1.SecretKeySelector{},
|
||||
URL: strToPtr("https://www.test.com"),
|
||||
URLSecret: &monitoringv1beta1.SecretKeySelector{
|
||||
Name: "creds",
|
||||
Key: "url",
|
||||
},
|
||||
},
|
||||
},
|
||||
WeChatConfigs: []monitoringv1alpha1.WeChatConfig{
|
||||
WeChatConfigs: []monitoringv1beta1.WeChatConfig{
|
||||
{
|
||||
APIURL: "https://test.com",
|
||||
},
|
||||
},
|
||||
EmailConfigs: []monitoringv1alpha1.EmailConfig{
|
||||
EmailConfigs: []monitoringv1beta1.EmailConfig{
|
||||
{
|
||||
To: "a",
|
||||
Smarthost: "b:8080",
|
||||
Headers: []monitoringv1alpha1.KeyValue{
|
||||
Headers: []monitoringv1beta1.KeyValue{
|
||||
{
|
||||
Key: "c",
|
||||
Value: "d",
|
||||
|
@ -403,10 +404,10 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
VictorOpsConfigs: []monitoringv1alpha1.VictorOpsConfig{
|
||||
VictorOpsConfigs: []monitoringv1beta1.VictorOpsConfig{
|
||||
{
|
||||
RoutingKey: "a",
|
||||
CustomFields: []monitoringv1alpha1.KeyValue{
|
||||
CustomFields: []monitoringv1beta1.KeyValue{
|
||||
{
|
||||
Key: "b",
|
||||
Value: "c",
|
||||
|
@ -414,29 +415,35 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
PushoverConfigs: []monitoringv1alpha1.PushoverConfig{
|
||||
PushoverConfigs: []monitoringv1beta1.PushoverConfig{
|
||||
{
|
||||
UserKey: &v1.SecretKeySelector{},
|
||||
Token: &v1.SecretKeySelector{},
|
||||
Retry: "10m",
|
||||
Expire: "5m",
|
||||
UserKey: &monitoringv1beta1.SecretKeySelector{
|
||||
Name: "creds",
|
||||
Key: "user",
|
||||
},
|
||||
Token: &monitoringv1beta1.SecretKeySelector{
|
||||
Name: "creds",
|
||||
Key: "token",
|
||||
},
|
||||
Retry: "10m",
|
||||
Expire: "5m",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &monitoringv1alpha1.Route{
|
||||
Route: &monitoringv1beta1.Route{
|
||||
Receiver: "same",
|
||||
GroupBy: []string{"..."},
|
||||
MuteTimeIntervals: []string{"weekdays-only"},
|
||||
},
|
||||
MuteTimeIntervals: []monitoringv1alpha1.MuteTimeInterval{
|
||||
TimeIntervals: []monitoringv1beta1.TimeInterval{
|
||||
{
|
||||
Name: "weekdays-only",
|
||||
TimeIntervals: []monitoringv1alpha1.TimeInterval{
|
||||
TimeIntervals: []monitoringv1beta1.TimePeriod{
|
||||
{
|
||||
Weekdays: []monitoringv1alpha1.WeekdayRange{
|
||||
monitoringv1alpha1.WeekdayRange("Saturday"),
|
||||
monitoringv1alpha1.WeekdayRange("Sunday"),
|
||||
Weekdays: []monitoringv1beta1.WeekdayRange{
|
||||
monitoringv1beta1.WeekdayRange("Saturday"),
|
||||
monitoringv1beta1.WeekdayRange("Sunday"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -465,54 +472,6 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestValidateUrl(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
expectErr bool
|
||||
expectResult func() *config.URL
|
||||
}{
|
||||
{
|
||||
name: "Test invalid url returns error",
|
||||
in: "https://!^invalid.com",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test missing scheme returns error",
|
||||
in: "is.normally.valid",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
in: "https://u:p@is.compliant.with.upstream.unmarshal",
|
||||
expectResult: func() *config.URL {
|
||||
u, _ := url.Parse("https://u:p@is.compliant.with.upstream.unmarshal")
|
||||
return &config.URL{URL: u}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
u, err := ValidateURL(tc.in)
|
||||
if tc.expectErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected error but got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
res := tc.expectResult()
|
||||
if !reflect.DeepEqual(u, res) {
|
||||
t.Fatalf("wanted %v but got %v", res, u)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func strToPtr(s string) *string {
|
||||
return &s
|
||||
}
|
70
pkg/alertmanager/validation/validation.go
Normal file
70
pkg/alertmanager/validation/validation.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2022 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/operator"
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
)
|
||||
|
||||
// ValidateAlertmanager runs extra validation on the AlertManager fields which
|
||||
// can't be done at the CRD schema validation level.
|
||||
func ValidateAlertmanager(am *monitoringv1.Alertmanager) error {
|
||||
if am.Spec.Retention != "" {
|
||||
if err := operator.ValidateDurationField(am.Spec.Retention); err != nil {
|
||||
return errors.Wrap(err, "invalid retention value specified")
|
||||
}
|
||||
}
|
||||
|
||||
if am.Spec.ClusterGossipInterval != "" {
|
||||
if err := operator.ValidateDurationField(am.Spec.ClusterGossipInterval); err != nil {
|
||||
return errors.Wrap(err, "invalid clusterGossipInterval value specified")
|
||||
}
|
||||
}
|
||||
|
||||
if am.Spec.ClusterPushpullInterval != "" {
|
||||
if err := operator.ValidateDurationField(am.Spec.ClusterPushpullInterval); err != nil {
|
||||
return errors.Wrap(err, "invalid clusterPushpullInterval value specified")
|
||||
}
|
||||
}
|
||||
|
||||
if am.Spec.ClusterPeerTimeout != "" {
|
||||
if err := operator.ValidateDurationField(am.Spec.ClusterPeerTimeout); err != nil {
|
||||
return errors.Wrap(err, "invalid clusterPeerTimeout value specified")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateAlertmanagerConfig checks that the given resource complies with the
|
||||
|
||||
// ValidateURL against the config.URL
|
||||
// This could potentially become a regex and be validated via OpenAPI
|
||||
// but right now, since we know we need to unmarshal into an upstream type
|
||||
// after conversion, we validate we don't error when doing so
|
||||
func ValidateURL(url string) (*config.URL, error) {
|
||||
var u config.URL
|
||||
err := json.Unmarshal([]byte(fmt.Sprintf(`"%s"`, url)), &u)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("validate url from string failed for %s: %w", url, err)
|
||||
}
|
||||
return &u, nil
|
||||
}
|
71
pkg/alertmanager/validation/validation_test.go
Normal file
71
pkg/alertmanager/validation/validation_test.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2021 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
)
|
||||
|
||||
func TestValidateUrl(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
expectErr bool
|
||||
expectResult func() *config.URL
|
||||
}{
|
||||
{
|
||||
name: "Test invalid url returns error",
|
||||
in: "https://!^invalid.com",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test missing scheme returns error",
|
||||
in: "is.normally.valid",
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
in: "https://u:p@is.compliant.with.upstream.unmarshal",
|
||||
expectResult: func() *config.URL {
|
||||
u, _ := url.Parse("https://u:p@is.compliant.with.upstream.unmarshal")
|
||||
return &config.URL{URL: u}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
u, err := ValidateURL(tc.in)
|
||||
if tc.expectErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected error but got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
res := tc.expectResult()
|
||||
if !reflect.DeepEqual(u, res) {
|
||||
t.Fatalf("wanted %v but got %v", res, u)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -3,9 +3,10 @@ module github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
k8s.io/api v0.23.0
|
||||
k8s.io/apiextensions-apiserver v0.23.0
|
||||
k8s.io/apimachinery v0.23.0
|
||||
k8s.io/api v0.23.5
|
||||
k8s.io/apiextensions-apiserver v0.23.5
|
||||
k8s.io/apimachinery v0.23.5
|
||||
sigs.k8s.io/controller-runtime v0.11.2
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -16,12 +17,12 @@ require (
|
|||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a // indirect
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.30.0 // indirect
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
)
|
||||
|
|
|
@ -117,6 +117,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
|||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
|
@ -124,6 +125,7 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD
|
|||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
|
@ -148,6 +150,7 @@ github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE
|
|||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
|
@ -259,7 +262,9 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
|||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
|
@ -324,14 +329,18 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
|
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
|
@ -448,11 +457,14 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
|
|||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
@ -541,10 +553,12 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -617,6 +631,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -630,8 +645,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -701,6 +718,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u
|
|||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
|
@ -712,6 +730,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
|
@ -860,16 +879,16 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.23.0 h1:WrL1gb73VSC8obi8cuYETJGXEoFNEh3LU0Pt+Sokgro=
|
||||
k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
|
||||
k8s.io/apiextensions-apiserver v0.23.0 h1:uii8BYmHYiT2ZTAJxmvc3X8UhNYMxl2A0z0Xq3Pm+WY=
|
||||
k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
|
||||
k8s.io/apimachinery v0.23.0 h1:mIfWRMjBuMdolAWJ3Fd+aPTMv3X9z+waiARMpvvb0HQ=
|
||||
k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
|
||||
k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4=
|
||||
k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
|
||||
k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
|
||||
k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI=
|
||||
k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA=
|
||||
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
|
||||
k8s.io/apiextensions-apiserver v0.23.5 h1:5SKzdXyvIJKu+zbfPc3kCbWpbxi+O+zdmAJBm26UJqI=
|
||||
k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
|
||||
k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0=
|
||||
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||
k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw=
|
||||
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
|
||||
k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||
k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
|
@ -877,16 +896,19 @@ k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
|
|||
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE=
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw=
|
||||
sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA=
|
||||
sigs.k8s.io/controller-runtime v0.11.2/go.mod h1:P6QCzrEjLaZGqHsfd+os7JQ+WFZhvB8MRFsn4dWF7O4=
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2022 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// Hub marks this type as a conversion hub.
|
||||
func (*AlertmanagerConfig) Hub() {}
|
|
@ -41,6 +41,7 @@ const (
|
|||
// +genclient
|
||||
// +k8s:openapi-gen=true
|
||||
// +kubebuilder:resource:categories="prometheus-operator",shortName="amcfg"
|
||||
// +kubebuilder:storageversion
|
||||
type AlertmanagerConfig struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
|
1075
pkg/apis/monitoring/v1beta1/alertmanager_config_types.go
Normal file
1075
pkg/apis/monitoring/v1beta1/alertmanager_config_types.go
Normal file
File diff suppressed because it is too large
Load diff
544
pkg/apis/monitoring/v1beta1/conversion_from.go
Normal file
544
pkg/apis/monitoring/v1beta1/conversion_from.go
Normal file
|
@ -0,0 +1,544 @@
|
|||
// Copyright 2022 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/conversion"
|
||||
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
)
|
||||
|
||||
func convertRouteFrom(in *v1alpha1.Route) (*Route, error) {
|
||||
if in == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
out := &Route{
|
||||
Receiver: in.Receiver,
|
||||
GroupBy: in.GroupBy,
|
||||
GroupWait: in.GroupWait,
|
||||
GroupInterval: in.GroupInterval,
|
||||
RepeatInterval: in.RepeatInterval,
|
||||
Matchers: convertMatchersFrom(in.Matchers),
|
||||
MuteTimeIntervals: in.MuteTimeIntervals,
|
||||
}
|
||||
|
||||
// Deserialize child routes to convert them to v1alpha1 and serialize back.
|
||||
crs, err := in.ChildRoutes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out.Routes = make([]apiextensionsv1.JSON, 0, len(in.Routes))
|
||||
for i := range crs {
|
||||
cr, err := convertRouteFrom(&crs[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("route[%d]: %w", i, err)
|
||||
}
|
||||
|
||||
b, err := json.Marshal(cr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("route[%d]: %w", i, err)
|
||||
}
|
||||
|
||||
out.Routes = append(out.Routes, apiextensionsv1.JSON{Raw: b})
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func convertMatchersFrom(in []v1alpha1.Matcher) []Matcher {
|
||||
out := make([]Matcher, 0, len(in))
|
||||
|
||||
for _, m := range in {
|
||||
mt := m.MatchType
|
||||
if mt == "" {
|
||||
mt = "="
|
||||
if m.Regex {
|
||||
mt = "=~"
|
||||
}
|
||||
}
|
||||
out = append(
|
||||
out,
|
||||
Matcher{
|
||||
Name: m.Name,
|
||||
Value: m.Value,
|
||||
MatchType: MatchType(mt),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertTimeIntervalsFrom(in []v1alpha1.TimeInterval) []TimePeriod {
|
||||
out := make([]TimePeriod, 0, len(in))
|
||||
|
||||
for _, ti := range in {
|
||||
var (
|
||||
trs = make([]TimeRange, 0, len(ti.Times))
|
||||
wds = make([]WeekdayRange, 0, len(ti.Weekdays))
|
||||
doms = make([]DayOfMonthRange, 0, len(ti.DaysOfMonth))
|
||||
mrs = make([]MonthRange, 0, len(ti.Months))
|
||||
yrs = make([]YearRange, 0, len(ti.Years))
|
||||
)
|
||||
|
||||
for _, tr := range ti.Times {
|
||||
trs = append(trs, TimeRange{StartTime: Time(tr.StartTime), EndTime: Time(tr.EndTime)})
|
||||
}
|
||||
|
||||
for _, wd := range ti.Weekdays {
|
||||
wds = append(wds, WeekdayRange(wd))
|
||||
}
|
||||
|
||||
for _, dm := range ti.DaysOfMonth {
|
||||
doms = append(doms, DayOfMonthRange{Start: dm.Start, End: dm.End})
|
||||
}
|
||||
|
||||
for _, mr := range ti.Months {
|
||||
mrs = append(mrs, MonthRange(mr))
|
||||
}
|
||||
|
||||
for _, yr := range ti.Years {
|
||||
yrs = append(yrs, YearRange(yr))
|
||||
}
|
||||
|
||||
out = append(
|
||||
out,
|
||||
TimePeriod{
|
||||
Times: trs,
|
||||
Weekdays: wds,
|
||||
DaysOfMonth: doms,
|
||||
Months: mrs,
|
||||
Years: yrs,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertHTTPConfigFrom(in *v1alpha1.HTTPConfig) *HTTPConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &HTTPConfig{
|
||||
Authorization: in.Authorization,
|
||||
BasicAuth: in.BasicAuth,
|
||||
OAuth2: in.OAuth2,
|
||||
BearerTokenSecret: convertSecretKeySelectorFrom(in.BearerTokenSecret),
|
||||
TLSConfig: in.TLSConfig,
|
||||
ProxyURL: in.ProxyURL,
|
||||
}
|
||||
}
|
||||
|
||||
func convertKeyValuesFrom(in []v1alpha1.KeyValue) []KeyValue {
|
||||
out := make([]KeyValue, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = KeyValue{
|
||||
Key: in[i].Key,
|
||||
Value: in[i].Value,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
|
||||
}
|
||||
|
||||
func convertSecretKeySelectorFrom(in *v1.SecretKeySelector) *SecretKeySelector {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &SecretKeySelector{
|
||||
Name: in.Name,
|
||||
Key: in.Key,
|
||||
}
|
||||
}
|
||||
|
||||
func convertOpsGenieConfigRespondersFrom(in []v1alpha1.OpsGenieConfigResponder) []OpsGenieConfigResponder {
|
||||
out := make([]OpsGenieConfigResponder, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = OpsGenieConfigResponder{
|
||||
ID: in[i].ID,
|
||||
Name: in[i].Name,
|
||||
Username: in[i].Username,
|
||||
Type: in[i].Type,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertOpsGenieConfigFrom(in v1alpha1.OpsGenieConfig) OpsGenieConfig {
|
||||
return OpsGenieConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APIKey: convertSecretKeySelectorFrom(in.APIKey),
|
||||
APIURL: in.APIURL,
|
||||
Message: in.Message,
|
||||
Description: in.Description,
|
||||
Source: in.Source,
|
||||
Tags: in.Tags,
|
||||
Note: in.Note,
|
||||
Priority: in.Priority,
|
||||
Details: convertKeyValuesFrom(in.Details),
|
||||
Responders: convertOpsGenieConfigRespondersFrom(in.Responders),
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
Entity: in.Entity,
|
||||
Actions: in.Actions,
|
||||
}
|
||||
}
|
||||
|
||||
func convertPagerDutyImageConfigsFrom(in []v1alpha1.PagerDutyImageConfig) []PagerDutyImageConfig {
|
||||
out := make([]PagerDutyImageConfig, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = PagerDutyImageConfig{
|
||||
Src: in[i].Src,
|
||||
Href: in[i].Href,
|
||||
Alt: in[i].Alt,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertPagerDutyLinkConfigsFrom(in []v1alpha1.PagerDutyLinkConfig) []PagerDutyLinkConfig {
|
||||
out := make([]PagerDutyLinkConfig, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = PagerDutyLinkConfig{
|
||||
Href: in[i].Href,
|
||||
Text: in[i].Text,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertPagerDutyConfigFrom(in v1alpha1.PagerDutyConfig) PagerDutyConfig {
|
||||
return PagerDutyConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
RoutingKey: convertSecretKeySelectorFrom(in.RoutingKey),
|
||||
ServiceKey: convertSecretKeySelectorFrom(in.ServiceKey),
|
||||
URL: in.URL,
|
||||
Client: in.Client,
|
||||
ClientURL: in.ClientURL,
|
||||
Description: in.Description,
|
||||
Severity: in.Severity,
|
||||
Class: in.Class,
|
||||
Group: in.Group,
|
||||
Component: in.Component,
|
||||
Details: convertKeyValuesFrom(in.Details),
|
||||
PagerDutyImageConfigs: convertPagerDutyImageConfigsFrom(in.PagerDutyImageConfigs),
|
||||
PagerDutyLinkConfigs: convertPagerDutyLinkConfigsFrom(in.PagerDutyLinkConfigs),
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertSlackFieldsFrom(in []v1alpha1.SlackField) []SlackField {
|
||||
out := make([]SlackField, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = SlackField{
|
||||
Title: in[i].Title,
|
||||
Value: in[i].Value,
|
||||
Short: in[i].Short,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertSlackActionsFrom(in []v1alpha1.SlackAction) []SlackAction {
|
||||
out := make([]SlackAction, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = SlackAction{
|
||||
Type: in[i].Type,
|
||||
Text: in[i].Text,
|
||||
URL: in[i].URL,
|
||||
Style: in[i].Style,
|
||||
Name: in[i].Name,
|
||||
Value: in[i].Value,
|
||||
}
|
||||
if in[i].ConfirmField != nil {
|
||||
out[i].ConfirmField = &SlackConfirmationField{
|
||||
Text: in[i].ConfirmField.Text,
|
||||
Title: in[i].ConfirmField.Title,
|
||||
OkText: in[i].ConfirmField.OkText,
|
||||
DismissText: in[i].ConfirmField.DismissText,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertSlackConfigFrom(in v1alpha1.SlackConfig) SlackConfig {
|
||||
return SlackConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APIURL: convertSecretKeySelectorFrom(in.APIURL),
|
||||
Channel: in.Channel,
|
||||
Username: in.Username,
|
||||
Color: in.Color,
|
||||
Title: in.Title,
|
||||
TitleLink: in.TitleLink,
|
||||
Pretext: in.Pretext,
|
||||
Text: in.Text,
|
||||
Fields: convertSlackFieldsFrom(in.Fields),
|
||||
ShortFields: in.ShortFields,
|
||||
Footer: in.Footer,
|
||||
Fallback: in.Fallback,
|
||||
CallbackID: in.CallbackID,
|
||||
IconEmoji: in.IconEmoji,
|
||||
IconURL: in.IconURL,
|
||||
ImageURL: in.ImageURL,
|
||||
ThumbURL: in.ThumbURL,
|
||||
LinkNames: in.LinkNames,
|
||||
MrkdwnIn: in.MrkdwnIn,
|
||||
Actions: convertSlackActionsFrom(in.Actions),
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertWebhookConfigFrom(in v1alpha1.WebhookConfig) WebhookConfig {
|
||||
return WebhookConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
URL: in.URL,
|
||||
URLSecret: convertSecretKeySelectorFrom(in.URLSecret),
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
MaxAlerts: in.MaxAlerts,
|
||||
}
|
||||
}
|
||||
|
||||
func convertWeChatConfigFrom(in v1alpha1.WeChatConfig) WeChatConfig {
|
||||
return WeChatConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APISecret: convertSecretKeySelectorFrom(in.APISecret),
|
||||
APIURL: in.APIURL,
|
||||
CorpID: in.CorpID,
|
||||
AgentID: in.AgentID,
|
||||
ToUser: in.ToUser,
|
||||
ToParty: in.ToParty,
|
||||
ToTag: in.ToTag,
|
||||
Message: in.Message,
|
||||
MessageType: in.MessageType,
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertEmailConfigFrom(in v1alpha1.EmailConfig) EmailConfig {
|
||||
return EmailConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
To: in.To,
|
||||
From: in.From,
|
||||
Hello: in.Hello,
|
||||
Smarthost: in.Smarthost,
|
||||
AuthUsername: in.AuthUsername,
|
||||
AuthPassword: convertSecretKeySelectorFrom(in.AuthPassword),
|
||||
AuthSecret: convertSecretKeySelectorFrom(in.AuthSecret),
|
||||
AuthIdentity: in.AuthIdentity,
|
||||
Headers: convertKeyValuesFrom(in.Headers),
|
||||
HTML: in.HTML,
|
||||
Text: in.Text,
|
||||
RequireTLS: in.RequireTLS,
|
||||
TLSConfig: in.TLSConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func convertVictorOpsConfigFrom(in v1alpha1.VictorOpsConfig) VictorOpsConfig {
|
||||
return VictorOpsConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APIKey: convertSecretKeySelectorFrom(in.APIKey),
|
||||
APIURL: in.APIURL,
|
||||
RoutingKey: in.RoutingKey,
|
||||
MessageType: in.MessageType,
|
||||
EntityDisplayName: in.EntityDisplayName,
|
||||
StateMessage: in.StateMessage,
|
||||
MonitoringTool: in.MonitoringTool,
|
||||
CustomFields: convertKeyValuesFrom(in.CustomFields),
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertPushoverConfigFrom(in v1alpha1.PushoverConfig) PushoverConfig {
|
||||
return PushoverConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
UserKey: convertSecretKeySelectorFrom(in.UserKey),
|
||||
Token: convertSecretKeySelectorFrom(in.Token),
|
||||
Title: in.Title,
|
||||
Message: in.Message,
|
||||
URL: in.URL,
|
||||
URLTitle: in.URLTitle,
|
||||
Sound: in.Sound,
|
||||
Priority: in.Priority,
|
||||
Retry: in.Retry,
|
||||
Expire: in.Expire,
|
||||
HTML: in.HTML,
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertSNSConfigFrom(in v1alpha1.SNSConfig) SNSConfig {
|
||||
return SNSConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
ApiURL: in.ApiURL,
|
||||
Sigv4: in.Sigv4,
|
||||
TopicARN: in.TopicARN,
|
||||
Subject: in.Subject,
|
||||
PhoneNumber: in.PhoneNumber,
|
||||
TargetARN: in.TargetARN,
|
||||
Message: in.Message,
|
||||
Attributes: in.Attributes,
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertTelegramConfigFrom(in v1alpha1.TelegramConfig) TelegramConfig {
|
||||
return TelegramConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APIURL: in.APIURL,
|
||||
BotToken: convertSecretKeySelectorFrom(in.BotToken),
|
||||
ChatID: in.ChatID,
|
||||
Message: in.Message,
|
||||
DisableNotifications: in.DisableNotifications,
|
||||
ParseMode: in.ParseMode,
|
||||
HTTPConfig: convertHTTPConfigFrom(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertFrom converts from the Hub version (v1alpha1) to this version (v1beta1).
|
||||
func (dst *AlertmanagerConfig) ConvertFrom(srcRaw conversion.Hub) error {
|
||||
src := srcRaw.(*v1alpha1.AlertmanagerConfig)
|
||||
|
||||
dst.ObjectMeta = src.ObjectMeta
|
||||
|
||||
for _, in := range src.Spec.Receivers {
|
||||
out := Receiver{
|
||||
Name: in.Name,
|
||||
}
|
||||
|
||||
for _, in := range in.OpsGenieConfigs {
|
||||
out.OpsGenieConfigs = append(
|
||||
out.OpsGenieConfigs,
|
||||
convertOpsGenieConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.PagerDutyConfigs {
|
||||
out.PagerDutyConfigs = append(
|
||||
out.PagerDutyConfigs,
|
||||
convertPagerDutyConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.SlackConfigs {
|
||||
out.SlackConfigs = append(
|
||||
out.SlackConfigs,
|
||||
convertSlackConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.WebhookConfigs {
|
||||
out.WebhookConfigs = append(
|
||||
out.WebhookConfigs,
|
||||
convertWebhookConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.WeChatConfigs {
|
||||
out.WeChatConfigs = append(
|
||||
out.WeChatConfigs,
|
||||
convertWeChatConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.EmailConfigs {
|
||||
out.EmailConfigs = append(
|
||||
out.EmailConfigs,
|
||||
convertEmailConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.VictorOpsConfigs {
|
||||
out.VictorOpsConfigs = append(
|
||||
out.VictorOpsConfigs,
|
||||
convertVictorOpsConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.PushoverConfigs {
|
||||
out.PushoverConfigs = append(
|
||||
out.PushoverConfigs,
|
||||
convertPushoverConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.SNSConfigs {
|
||||
out.SNSConfigs = append(
|
||||
out.SNSConfigs,
|
||||
convertSNSConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.TelegramConfigs {
|
||||
out.TelegramConfigs = append(
|
||||
out.TelegramConfigs,
|
||||
convertTelegramConfigFrom(in),
|
||||
)
|
||||
}
|
||||
|
||||
dst.Spec.Receivers = append(dst.Spec.Receivers, out)
|
||||
}
|
||||
|
||||
for _, in := range src.Spec.InhibitRules {
|
||||
dst.Spec.InhibitRules = append(
|
||||
dst.Spec.InhibitRules,
|
||||
InhibitRule{
|
||||
TargetMatch: convertMatchersFrom(in.TargetMatch),
|
||||
SourceMatch: convertMatchersFrom(in.SourceMatch),
|
||||
Equal: in.Equal,
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
for _, in := range src.Spec.MuteTimeIntervals {
|
||||
dst.Spec.TimeIntervals = append(
|
||||
dst.Spec.TimeIntervals,
|
||||
TimeInterval{
|
||||
Name: in.Name,
|
||||
TimeIntervals: convertTimeIntervalsFrom(in.TimeIntervals),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
r, err := convertRouteFrom(src.Spec.Route)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dst.Spec.Route = r
|
||||
|
||||
return nil
|
||||
}
|
539
pkg/apis/monitoring/v1beta1/conversion_to.go
Normal file
539
pkg/apis/monitoring/v1beta1/conversion_to.go
Normal file
|
@ -0,0 +1,539 @@
|
|||
// Copyright 2022 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/conversion"
|
||||
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
)
|
||||
|
||||
func convertRouteTo(in *Route) (*v1alpha1.Route, error) {
|
||||
if in == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
out := &v1alpha1.Route{
|
||||
Receiver: in.Receiver,
|
||||
GroupBy: in.GroupBy,
|
||||
GroupWait: in.GroupWait,
|
||||
GroupInterval: in.GroupInterval,
|
||||
RepeatInterval: in.RepeatInterval,
|
||||
Matchers: convertMatchersTo(in.Matchers),
|
||||
MuteTimeIntervals: in.MuteTimeIntervals,
|
||||
}
|
||||
|
||||
// Deserialize child routes to convert them to v1alpha1 and serialize back.
|
||||
crs, err := in.ChildRoutes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out.Routes = make([]apiextensionsv1.JSON, 0, len(in.Routes))
|
||||
for i := range crs {
|
||||
cr, err := convertRouteTo(&crs[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("route[%d]: %w", i, err)
|
||||
}
|
||||
|
||||
b, err := json.Marshal(cr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("route[%d]: %w", i, err)
|
||||
}
|
||||
|
||||
out.Routes = append(out.Routes, apiextensionsv1.JSON{Raw: b})
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func convertMatchersTo(in []Matcher) []v1alpha1.Matcher {
|
||||
out := make([]v1alpha1.Matcher, 0, len(in))
|
||||
|
||||
for _, m := range in {
|
||||
out = append(
|
||||
out,
|
||||
v1alpha1.Matcher{
|
||||
Name: m.Name,
|
||||
Value: m.Value,
|
||||
MatchType: v1alpha1.MatchType(m.MatchType),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertTimeIntervalsTo(in []TimePeriod) []v1alpha1.TimeInterval {
|
||||
out := make([]v1alpha1.TimeInterval, 0, len(in))
|
||||
|
||||
for _, ti := range in {
|
||||
var (
|
||||
trs = make([]v1alpha1.TimeRange, 0, len(ti.Times))
|
||||
wds = make([]v1alpha1.WeekdayRange, 0, len(ti.Weekdays))
|
||||
doms = make([]v1alpha1.DayOfMonthRange, 0, len(ti.DaysOfMonth))
|
||||
mrs = make([]v1alpha1.MonthRange, 0, len(ti.Months))
|
||||
yrs = make([]v1alpha1.YearRange, 0, len(ti.Years))
|
||||
)
|
||||
|
||||
for _, tr := range ti.Times {
|
||||
trs = append(trs, v1alpha1.TimeRange{StartTime: v1alpha1.Time(tr.StartTime), EndTime: v1alpha1.Time(tr.EndTime)})
|
||||
}
|
||||
|
||||
for _, wd := range ti.Weekdays {
|
||||
wds = append(wds, v1alpha1.WeekdayRange(wd))
|
||||
}
|
||||
|
||||
for _, dm := range ti.DaysOfMonth {
|
||||
doms = append(doms, v1alpha1.DayOfMonthRange{Start: dm.Start, End: dm.End})
|
||||
}
|
||||
|
||||
for _, mr := range ti.Months {
|
||||
mrs = append(mrs, v1alpha1.MonthRange(mr))
|
||||
}
|
||||
|
||||
for _, yr := range ti.Years {
|
||||
yrs = append(yrs, v1alpha1.YearRange(yr))
|
||||
}
|
||||
|
||||
out = append(
|
||||
out,
|
||||
v1alpha1.TimeInterval{
|
||||
Times: trs,
|
||||
Weekdays: wds,
|
||||
DaysOfMonth: doms,
|
||||
Months: mrs,
|
||||
Years: yrs,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertHTTPConfigTo(in *HTTPConfig) *v1alpha1.HTTPConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &v1alpha1.HTTPConfig{
|
||||
Authorization: in.Authorization,
|
||||
BasicAuth: in.BasicAuth,
|
||||
OAuth2: in.OAuth2,
|
||||
BearerTokenSecret: convertSecretKeySelectorTo(in.BearerTokenSecret),
|
||||
TLSConfig: in.TLSConfig,
|
||||
ProxyURL: in.ProxyURL,
|
||||
}
|
||||
}
|
||||
|
||||
func convertKeyValuesTo(in []KeyValue) []v1alpha1.KeyValue {
|
||||
out := make([]v1alpha1.KeyValue, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = v1alpha1.KeyValue{
|
||||
Key: in[i].Key,
|
||||
Value: in[i].Value,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
|
||||
}
|
||||
|
||||
func convertSecretKeySelectorTo(in *SecretKeySelector) *v1.SecretKeySelector {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &v1.SecretKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: in.Name,
|
||||
},
|
||||
Key: in.Key,
|
||||
}
|
||||
}
|
||||
|
||||
func convertOpsGenieConfigRespondersTo(in []OpsGenieConfigResponder) []v1alpha1.OpsGenieConfigResponder {
|
||||
out := make([]v1alpha1.OpsGenieConfigResponder, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = v1alpha1.OpsGenieConfigResponder{
|
||||
ID: in[i].ID,
|
||||
Name: in[i].Name,
|
||||
Username: in[i].Username,
|
||||
Type: in[i].Type,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertOpsGenieConfigTo(in OpsGenieConfig) v1alpha1.OpsGenieConfig {
|
||||
return v1alpha1.OpsGenieConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APIKey: convertSecretKeySelectorTo(in.APIKey),
|
||||
APIURL: in.APIURL,
|
||||
Message: in.Message,
|
||||
Description: in.Description,
|
||||
Source: in.Source,
|
||||
Tags: in.Tags,
|
||||
Note: in.Note,
|
||||
Priority: in.Priority,
|
||||
Details: convertKeyValuesTo(in.Details),
|
||||
Responders: convertOpsGenieConfigRespondersTo(in.Responders),
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
Entity: in.Entity,
|
||||
Actions: in.Actions,
|
||||
}
|
||||
}
|
||||
|
||||
func convertPagerDutyImageConfigsTo(in []PagerDutyImageConfig) []v1alpha1.PagerDutyImageConfig {
|
||||
out := make([]v1alpha1.PagerDutyImageConfig, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = v1alpha1.PagerDutyImageConfig{
|
||||
Src: in[i].Src,
|
||||
Href: in[i].Href,
|
||||
Alt: in[i].Alt,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertPagerDutyLinkConfigsTo(in []PagerDutyLinkConfig) []v1alpha1.PagerDutyLinkConfig {
|
||||
out := make([]v1alpha1.PagerDutyLinkConfig, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = v1alpha1.PagerDutyLinkConfig{
|
||||
Href: in[i].Href,
|
||||
Text: in[i].Text,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertPagerDutyConfigTo(in PagerDutyConfig) v1alpha1.PagerDutyConfig {
|
||||
return v1alpha1.PagerDutyConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
RoutingKey: convertSecretKeySelectorTo(in.RoutingKey),
|
||||
ServiceKey: convertSecretKeySelectorTo(in.ServiceKey),
|
||||
URL: in.URL,
|
||||
Client: in.Client,
|
||||
ClientURL: in.ClientURL,
|
||||
Description: in.Description,
|
||||
Severity: in.Severity,
|
||||
Class: in.Class,
|
||||
Group: in.Group,
|
||||
Component: in.Component,
|
||||
Details: convertKeyValuesTo(in.Details),
|
||||
PagerDutyImageConfigs: convertPagerDutyImageConfigsTo(in.PagerDutyImageConfigs),
|
||||
PagerDutyLinkConfigs: convertPagerDutyLinkConfigsTo(in.PagerDutyLinkConfigs),
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertSlackFieldsTo(in []SlackField) []v1alpha1.SlackField {
|
||||
out := make([]v1alpha1.SlackField, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = v1alpha1.SlackField{
|
||||
Title: in[i].Title,
|
||||
Value: in[i].Value,
|
||||
Short: in[i].Short,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertSlackActionsTo(in []SlackAction) []v1alpha1.SlackAction {
|
||||
out := make([]v1alpha1.SlackAction, len(in))
|
||||
|
||||
for i := range in {
|
||||
out[i] = v1alpha1.SlackAction{
|
||||
Type: in[i].Type,
|
||||
Text: in[i].Text,
|
||||
URL: in[i].URL,
|
||||
Style: in[i].Style,
|
||||
Name: in[i].Name,
|
||||
Value: in[i].Value,
|
||||
}
|
||||
if in[i].ConfirmField != nil {
|
||||
out[i].ConfirmField = &v1alpha1.SlackConfirmationField{
|
||||
Text: in[i].ConfirmField.Text,
|
||||
Title: in[i].ConfirmField.Title,
|
||||
OkText: in[i].ConfirmField.OkText,
|
||||
DismissText: in[i].ConfirmField.DismissText,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func convertSlackConfigTo(in SlackConfig) v1alpha1.SlackConfig {
|
||||
return v1alpha1.SlackConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APIURL: convertSecretKeySelectorTo(in.APIURL),
|
||||
Channel: in.Channel,
|
||||
Username: in.Username,
|
||||
Color: in.Color,
|
||||
Title: in.Title,
|
||||
TitleLink: in.TitleLink,
|
||||
Pretext: in.Pretext,
|
||||
Text: in.Text,
|
||||
Fields: convertSlackFieldsTo(in.Fields),
|
||||
ShortFields: in.ShortFields,
|
||||
Footer: in.Footer,
|
||||
Fallback: in.Fallback,
|
||||
CallbackID: in.CallbackID,
|
||||
IconEmoji: in.IconEmoji,
|
||||
IconURL: in.IconURL,
|
||||
ImageURL: in.ImageURL,
|
||||
ThumbURL: in.ThumbURL,
|
||||
LinkNames: in.LinkNames,
|
||||
MrkdwnIn: in.MrkdwnIn,
|
||||
Actions: convertSlackActionsTo(in.Actions),
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertWebhookConfigTo(in WebhookConfig) v1alpha1.WebhookConfig {
|
||||
return v1alpha1.WebhookConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
URL: in.URL,
|
||||
URLSecret: convertSecretKeySelectorTo(in.URLSecret),
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
MaxAlerts: in.MaxAlerts,
|
||||
}
|
||||
}
|
||||
|
||||
func convertWeChatConfigTo(in WeChatConfig) v1alpha1.WeChatConfig {
|
||||
return v1alpha1.WeChatConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APISecret: convertSecretKeySelectorTo(in.APISecret),
|
||||
APIURL: in.APIURL,
|
||||
CorpID: in.CorpID,
|
||||
AgentID: in.AgentID,
|
||||
ToUser: in.ToUser,
|
||||
ToParty: in.ToParty,
|
||||
ToTag: in.ToTag,
|
||||
Message: in.Message,
|
||||
MessageType: in.MessageType,
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertEmailConfigTo(in EmailConfig) v1alpha1.EmailConfig {
|
||||
return v1alpha1.EmailConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
To: in.To,
|
||||
From: in.From,
|
||||
Hello: in.Hello,
|
||||
Smarthost: in.Smarthost,
|
||||
AuthUsername: in.AuthUsername,
|
||||
AuthPassword: convertSecretKeySelectorTo(in.AuthPassword),
|
||||
AuthSecret: convertSecretKeySelectorTo(in.AuthSecret),
|
||||
AuthIdentity: in.AuthIdentity,
|
||||
Headers: convertKeyValuesTo(in.Headers),
|
||||
HTML: in.HTML,
|
||||
Text: in.Text,
|
||||
RequireTLS: in.RequireTLS,
|
||||
TLSConfig: in.TLSConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func convertVictorOpsConfigTo(in VictorOpsConfig) v1alpha1.VictorOpsConfig {
|
||||
return v1alpha1.VictorOpsConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APIKey: convertSecretKeySelectorTo(in.APIKey),
|
||||
APIURL: in.APIURL,
|
||||
RoutingKey: in.RoutingKey,
|
||||
MessageType: in.MessageType,
|
||||
EntityDisplayName: in.EntityDisplayName,
|
||||
StateMessage: in.StateMessage,
|
||||
MonitoringTool: in.MonitoringTool,
|
||||
CustomFields: convertKeyValuesTo(in.CustomFields),
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertPushoverConfigTo(in PushoverConfig) v1alpha1.PushoverConfig {
|
||||
return v1alpha1.PushoverConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
UserKey: convertSecretKeySelectorTo(in.UserKey),
|
||||
Token: convertSecretKeySelectorTo(in.Token),
|
||||
Title: in.Title,
|
||||
Message: in.Message,
|
||||
URL: in.URL,
|
||||
URLTitle: in.URLTitle,
|
||||
Sound: in.Sound,
|
||||
Priority: in.Priority,
|
||||
Retry: in.Retry,
|
||||
Expire: in.Expire,
|
||||
HTML: in.HTML,
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertSNSConfigTo(in SNSConfig) v1alpha1.SNSConfig {
|
||||
return v1alpha1.SNSConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
ApiURL: in.ApiURL,
|
||||
Sigv4: in.Sigv4,
|
||||
TopicARN: in.TopicARN,
|
||||
Subject: in.Subject,
|
||||
PhoneNumber: in.PhoneNumber,
|
||||
TargetARN: in.TargetARN,
|
||||
Message: in.Message,
|
||||
Attributes: in.Attributes,
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func convertTelegramConfigTo(in TelegramConfig) v1alpha1.TelegramConfig {
|
||||
return v1alpha1.TelegramConfig{
|
||||
SendResolved: in.SendResolved,
|
||||
APIURL: in.APIURL,
|
||||
BotToken: convertSecretKeySelectorTo(in.BotToken),
|
||||
ChatID: in.ChatID,
|
||||
Message: in.Message,
|
||||
DisableNotifications: in.DisableNotifications,
|
||||
ParseMode: in.ParseMode,
|
||||
HTTPConfig: convertHTTPConfigTo(in.HTTPConfig),
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertTo converts from this version (v1beta1) to the Hub version (v1alpha1).
|
||||
func (src *AlertmanagerConfig) ConvertTo(dstRaw conversion.Hub) error {
|
||||
dst := dstRaw.(*v1alpha1.AlertmanagerConfig)
|
||||
|
||||
dst.ObjectMeta = src.ObjectMeta
|
||||
|
||||
for _, in := range src.Spec.Receivers {
|
||||
out := v1alpha1.Receiver{
|
||||
Name: in.Name,
|
||||
}
|
||||
|
||||
for _, in := range in.OpsGenieConfigs {
|
||||
out.OpsGenieConfigs = append(
|
||||
out.OpsGenieConfigs,
|
||||
convertOpsGenieConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.PagerDutyConfigs {
|
||||
out.PagerDutyConfigs = append(
|
||||
out.PagerDutyConfigs,
|
||||
convertPagerDutyConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.SlackConfigs {
|
||||
out.SlackConfigs = append(
|
||||
out.SlackConfigs,
|
||||
convertSlackConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.WebhookConfigs {
|
||||
out.WebhookConfigs = append(
|
||||
out.WebhookConfigs,
|
||||
convertWebhookConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.WeChatConfigs {
|
||||
out.WeChatConfigs = append(
|
||||
out.WeChatConfigs,
|
||||
convertWeChatConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.EmailConfigs {
|
||||
out.EmailConfigs = append(
|
||||
out.EmailConfigs,
|
||||
convertEmailConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.VictorOpsConfigs {
|
||||
out.VictorOpsConfigs = append(
|
||||
out.VictorOpsConfigs,
|
||||
convertVictorOpsConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.PushoverConfigs {
|
||||
out.PushoverConfigs = append(
|
||||
out.PushoverConfigs,
|
||||
convertPushoverConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.SNSConfigs {
|
||||
out.SNSConfigs = append(
|
||||
out.SNSConfigs,
|
||||
convertSNSConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
for _, in := range in.TelegramConfigs {
|
||||
out.TelegramConfigs = append(
|
||||
out.TelegramConfigs,
|
||||
convertTelegramConfigTo(in),
|
||||
)
|
||||
}
|
||||
|
||||
dst.Spec.Receivers = append(dst.Spec.Receivers, out)
|
||||
}
|
||||
|
||||
for _, in := range src.Spec.InhibitRules {
|
||||
dst.Spec.InhibitRules = append(
|
||||
dst.Spec.InhibitRules,
|
||||
v1alpha1.InhibitRule{
|
||||
TargetMatch: convertMatchersTo(in.TargetMatch),
|
||||
SourceMatch: convertMatchersTo(in.SourceMatch),
|
||||
Equal: in.Equal,
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
for _, in := range src.Spec.TimeIntervals {
|
||||
dst.Spec.MuteTimeIntervals = append(
|
||||
dst.Spec.MuteTimeIntervals,
|
||||
v1alpha1.MuteTimeInterval{
|
||||
Name: in.Name,
|
||||
TimeIntervals: convertTimeIntervalsTo(in.TimeIntervals),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
r, err := convertRouteTo(src.Spec.Route)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dst.Spec.Route = r
|
||||
|
||||
return nil
|
||||
}
|
18
pkg/apis/monitoring/v1beta1/doc.go
Normal file
18
pkg/apis/monitoring/v1beta1/doc.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2020 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +groupName=monitoring.coreos.com
|
||||
|
||||
package v1beta1
|
55
pkg/apis/monitoring/v1beta1/register.go
Normal file
55
pkg/apis/monitoring/v1beta1/register.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2020 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring"
|
||||
)
|
||||
|
||||
// SchemeGroupVersion is the group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: monitoring.GroupName, Version: Version}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addKnownTypes)
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&AlertmanagerConfig{},
|
||||
&AlertmanagerConfigList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
348
pkg/apis/monitoring/v1beta1/validation.go
Normal file
348
pkg/apis/monitoring/v1beta1/validation.go
Normal file
|
@ -0,0 +1,348 @@
|
|||
// Copyright 2021 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (hc *HTTPConfig) Validate() error {
|
||||
if hc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if (hc.BasicAuth != nil || hc.OAuth2 != nil) && (hc.BearerTokenSecret != nil) {
|
||||
return fmt.Errorf("at most one of basicAuth, oauth2, bearerTokenSecret must be configured")
|
||||
}
|
||||
|
||||
if hc.Authorization != nil {
|
||||
if hc.BearerTokenSecret != nil {
|
||||
return fmt.Errorf("authorization is not compatible with bearerTokenSecret")
|
||||
}
|
||||
|
||||
if hc.BasicAuth != nil || hc.OAuth2 != nil {
|
||||
return fmt.Errorf("at most one of basicAuth, oauth2 & authorization must be configured")
|
||||
}
|
||||
|
||||
if err := hc.Authorization.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if hc.OAuth2 != nil {
|
||||
if hc.BasicAuth != nil {
|
||||
return fmt.Errorf("at most one of basicAuth, oauth2 & authorization must be configured")
|
||||
}
|
||||
|
||||
if err := hc.OAuth2.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if hc.TLSConfig != nil {
|
||||
if err := hc.TLSConfig.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate the TimeInterval
|
||||
func (ti TimeInterval) Validate() error {
|
||||
if ti.Name == "" {
|
||||
return errors.New("empty name field for time interval")
|
||||
}
|
||||
|
||||
for i, ti := range ti.TimeIntervals {
|
||||
for _, time := range ti.Times {
|
||||
if err := time.Validate(); err != nil {
|
||||
return fmt.Errorf("time range at %d is invalid: %w", i, err)
|
||||
}
|
||||
}
|
||||
for _, weekday := range ti.Weekdays {
|
||||
if err := weekday.Validate(); err != nil {
|
||||
return fmt.Errorf("weekday range at %d is invalid: %w", i, err)
|
||||
}
|
||||
}
|
||||
for _, dom := range ti.DaysOfMonth {
|
||||
if err := dom.Validate(); err != nil {
|
||||
return fmt.Errorf("day of month range at %d is invalid: %w", i, err)
|
||||
}
|
||||
}
|
||||
for _, month := range ti.Months {
|
||||
if err := month.Validate(); err != nil {
|
||||
return fmt.Errorf("month range at %d is invalid: %w", i, err)
|
||||
}
|
||||
}
|
||||
for _, year := range ti.Years {
|
||||
if err := year.Validate(); err != nil {
|
||||
return fmt.Errorf("year range at %d is invalid: %w", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate the TimeRange
|
||||
func (tr TimeRange) Validate() error {
|
||||
_, err := tr.Parse()
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse returns a ParsedRange on valid input or an error if the fields cannot be parsed
|
||||
// End of the day is represented as 1440.
|
||||
func (tr TimeRange) Parse() (*ParsedRange, error) {
|
||||
if tr.StartTime == "" || tr.EndTime == "" {
|
||||
return nil, fmt.Errorf("start and end are required")
|
||||
}
|
||||
|
||||
start, err := parseTime(string(tr.StartTime))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("start time invalid: %w", err)
|
||||
}
|
||||
|
||||
end, err := parseTime(string(tr.EndTime))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("end time invalid: %w", err)
|
||||
}
|
||||
|
||||
if start >= end {
|
||||
return nil, fmt.Errorf("start time %d cannot be equal or greater than end time %d", start, end)
|
||||
}
|
||||
return &ParsedRange{
|
||||
Start: start,
|
||||
End: end,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Validate the WeekdayRange
|
||||
func (wr WeekdayRange) Validate() error {
|
||||
_, err := wr.Parse()
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse returns a ParsedRange on valid input or an error if the fields cannot be parsed
|
||||
// The week starts on Sunday -> 0
|
||||
func (wr WeekdayRange) Parse() (*ParsedRange, error) {
|
||||
startStr, endStr, err := parseRange(string(wr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
start, err := Weekday(startStr).Int()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse start day from weekday range: %w", err)
|
||||
}
|
||||
|
||||
end, err := Weekday(endStr).Int()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse end day from weekday range: %w", err)
|
||||
}
|
||||
|
||||
if start > end {
|
||||
return nil, errors.New("start day cannot be before end day")
|
||||
}
|
||||
if start < 0 || start > 6 {
|
||||
return nil, fmt.Errorf("%s is not a valid day of the week: out of range", startStr)
|
||||
}
|
||||
if end < 0 || end > 6 {
|
||||
return nil, fmt.Errorf("%s is not a valid day of the week: out of range", endStr)
|
||||
}
|
||||
return &ParsedRange{Start: start, End: end}, nil
|
||||
}
|
||||
|
||||
// Validate the YearRange
|
||||
func (yr YearRange) Validate() error {
|
||||
_, err := yr.Parse()
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse returns a ParsedRange on valid input or an error if the fields cannot be parsed
|
||||
func (yr YearRange) Parse() (*ParsedRange, error) {
|
||||
startStr, endStr, err := parseRange(string(yr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
start, err := strconv.Atoi(startStr)
|
||||
if err != nil {
|
||||
fmt.Errorf("start year cannot be %s parsed: %w", startStr, err)
|
||||
}
|
||||
|
||||
end, err := strconv.Atoi(endStr)
|
||||
if err != nil {
|
||||
fmt.Errorf("end year cannot be %s parsed: %w", endStr, err)
|
||||
}
|
||||
|
||||
if start > end {
|
||||
return nil, fmt.Errorf("end year %d is before start year %d", end, start)
|
||||
}
|
||||
return &ParsedRange{Start: start, End: end}, nil
|
||||
}
|
||||
|
||||
// Int returns an integer, which is the canonical representation
|
||||
// of the Weekday in upstream types.
|
||||
// Returns an error if the Weekday is invalid
|
||||
func (w Weekday) Int() (int, error) {
|
||||
normaliseWeekday := Weekday(strings.ToLower(string(w)))
|
||||
|
||||
day, found := daysOfWeek[normaliseWeekday]
|
||||
if !found {
|
||||
i, err := strconv.Atoi(string(normaliseWeekday))
|
||||
if err != nil {
|
||||
return day, fmt.Errorf("%s is an invalid weekday", w)
|
||||
}
|
||||
day = i
|
||||
}
|
||||
|
||||
return day, nil
|
||||
}
|
||||
|
||||
// Int validates the Month and returns an integer, which is the canonical representation
|
||||
// of the Month in upstream types.
|
||||
// Returns an error if the Month is invalid
|
||||
func (m Month) Int() (int, error) {
|
||||
normaliseMonth := Month(strings.ToLower(string(m)))
|
||||
|
||||
day, found := months[normaliseMonth]
|
||||
if !found {
|
||||
i, err := strconv.Atoi(string(normaliseMonth))
|
||||
if err != nil {
|
||||
return day, fmt.Errorf("%s is an invalid month", m)
|
||||
}
|
||||
day = i
|
||||
}
|
||||
|
||||
return day, nil
|
||||
}
|
||||
|
||||
// Validate the DayOfMonthRange
|
||||
func (r DayOfMonthRange) Validate() error {
|
||||
// Note: Validation is copied from UnmarshalYAML for DayOfMonthRange in alertmanager repo
|
||||
|
||||
// Check beginning <= end accounting for negatives day of month indices as well.
|
||||
// Months != 31 days can't be addressed here and are clamped, but at least we can catch blatant errors.
|
||||
if r.Start == 0 || r.Start < -31 || r.Start > 31 {
|
||||
return fmt.Errorf("%d is not a valid day of the month: out of range", r.Start)
|
||||
}
|
||||
if r.End == 0 || r.End < -31 || r.End > 31 {
|
||||
return fmt.Errorf("%d is not a valid day of the month: out of range", r.End)
|
||||
}
|
||||
// Restricting here prevents errors where begin > end in longer months but not shorter months.
|
||||
if r.Start < 0 && r.End > 0 {
|
||||
return fmt.Errorf("end day must be negative if start day is negative")
|
||||
}
|
||||
// Check begin <= end. We can't know this for sure when using negative indices,
|
||||
// but we can prevent cases where its always invalid (using 28 day minimum length).
|
||||
checkBegin := r.Start
|
||||
checkEnd := r.End
|
||||
if r.Start < 0 {
|
||||
checkBegin = 28 + r.Start
|
||||
}
|
||||
if r.End < 0 {
|
||||
checkEnd = 28 + r.End
|
||||
}
|
||||
if checkBegin > checkEnd {
|
||||
return fmt.Errorf("end day %d is always before start day %d", r.End, r.Start)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate the month range
|
||||
func (mr MonthRange) Validate() error {
|
||||
_, err := mr.Parse()
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse returns a ParsedMonthRange or error on invalid input
|
||||
func (mr MonthRange) Parse() (*ParsedRange, error) {
|
||||
startStr, endStr, err := parseRange(string(mr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
start, err := Month(startStr).Int()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse start month from month range: %w", err)
|
||||
}
|
||||
|
||||
end, err := Month(endStr).Int()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse start month from month range: %w", err)
|
||||
}
|
||||
|
||||
if start > end {
|
||||
return nil, fmt.Errorf("end month %s is before start month %s", endStr, startStr)
|
||||
}
|
||||
return &ParsedRange{
|
||||
Start: start,
|
||||
End: end,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParsedRange is an integer representation of a range
|
||||
// +kubebuilder:object:generate:=false
|
||||
type ParsedRange struct {
|
||||
// Start is the beginning of the range
|
||||
Start int `json:"start,omitempty"`
|
||||
// End of the range
|
||||
End int `json:"end,omitempty"`
|
||||
}
|
||||
|
||||
var validTime = "^((([01][0-9])|(2[0-3])):[0-5][0-9])$|(^24:00$)"
|
||||
var validTimeRE = regexp.MustCompile(validTime)
|
||||
|
||||
// Converts a string of the form "HH:MM" into the number of minutes elapsed in the day.
|
||||
func parseTime(in string) (mins int, err error) {
|
||||
if !validTimeRE.MatchString(in) {
|
||||
return 0, fmt.Errorf("couldn't parse timestamp %s, invalid format", in)
|
||||
}
|
||||
timestampComponents := strings.Split(in, ":")
|
||||
if len(timestampComponents) != 2 {
|
||||
return 0, fmt.Errorf("invalid timestamp format: %s", in)
|
||||
}
|
||||
timeStampHours, err := strconv.Atoi(timestampComponents[0])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
timeStampMinutes, err := strconv.Atoi(timestampComponents[1])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if timeStampHours < 0 || timeStampHours > 24 || timeStampMinutes < 0 || timeStampMinutes > 60 {
|
||||
return 0, fmt.Errorf("timestamp %s out of range", in)
|
||||
}
|
||||
// Timestamps are stored as minutes elapsed in the day, so multiply hours by 60.
|
||||
mins = timeStampHours*60 + timeStampMinutes
|
||||
return mins, nil
|
||||
}
|
||||
|
||||
// parseRange parses a valid range string into parts
|
||||
func parseRange(in string) (start, end string, err error) {
|
||||
if !strings.ContainsRune(in, ':') {
|
||||
return in, in, nil
|
||||
}
|
||||
|
||||
parts := strings.Split(string(in), ":")
|
||||
if len(parts) != 2 {
|
||||
return start, end, fmt.Errorf("invalid range provided %s", in)
|
||||
}
|
||||
return parts[0], parts[1], nil
|
||||
}
|
345
pkg/apis/monitoring/v1beta1/validation_test.go
Normal file
345
pkg/apis/monitoring/v1beta1/validation_test.go
Normal file
|
@ -0,0 +1,345 @@
|
|||
// Copyright 2021 The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTimeRange_Parse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
in TimeRange
|
||||
expectErr bool
|
||||
expectResult *ParsedRange
|
||||
}{
|
||||
{
|
||||
name: "Test invalid time string produces error",
|
||||
in: TimeRange{
|
||||
StartTime: "16:00",
|
||||
EndTime: "25:00",
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid negative string produces error",
|
||||
in: TimeRange{
|
||||
StartTime: "-16:00",
|
||||
EndTime: "24:00",
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test end time earlier than start time is invalid",
|
||||
in: TimeRange{
|
||||
StartTime: "16:00",
|
||||
EndTime: "14:00",
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
in: TimeRange{
|
||||
StartTime: "12:00",
|
||||
EndTime: "24:00",
|
||||
},
|
||||
expectResult: &ParsedRange{
|
||||
Start: 720,
|
||||
End: 1440,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := tc.in.Parse()
|
||||
if tc.expectErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected err but got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error but got %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.expectResult) {
|
||||
t.Fatalf("wanted %v, but got %v", tc.expectResult, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonthRange_Parse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
in MonthRange
|
||||
expectErr bool
|
||||
expectResult *ParsedRange
|
||||
}{
|
||||
{
|
||||
name: "Test invalid range - more than two months returns an error",
|
||||
in: MonthRange("january:march:december"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid months returns error",
|
||||
in: MonthRange("januarE"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid months in range returns error",
|
||||
in: MonthRange("january:Merch"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid range - end before start returns error",
|
||||
in: MonthRange("march:january"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
in: MonthRange("january"),
|
||||
expectResult: &ParsedRange{
|
||||
Start: 1,
|
||||
End: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test happy path range",
|
||||
in: MonthRange("january:march"),
|
||||
expectResult: &ParsedRange{
|
||||
Start: 1,
|
||||
End: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := tc.in.Parse()
|
||||
if tc.expectErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected err but got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error but got %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.expectResult) {
|
||||
t.Fatalf("wanted %v, but got %v", tc.expectResult, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWeekdayRange_Parse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
in WeekdayRange
|
||||
expectErr bool
|
||||
expectResult *ParsedRange
|
||||
}{
|
||||
{
|
||||
name: "Test invalid range - more than two days returns an error",
|
||||
in: WeekdayRange("monday:wednesday:friday"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid day returns error",
|
||||
in: WeekdayRange("onday"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid days in range returns error",
|
||||
in: WeekdayRange("monday:friyay"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid range - end before start returns error",
|
||||
in: WeekdayRange("friday:monday"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
in: WeekdayRange("monday"),
|
||||
expectResult: &ParsedRange{
|
||||
Start: 1,
|
||||
End: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test happy path range",
|
||||
in: WeekdayRange("monday:wednesday"),
|
||||
expectResult: &ParsedRange{
|
||||
Start: 1,
|
||||
End: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := tc.in.Parse()
|
||||
if tc.expectErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected err but got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error but got %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.expectResult) {
|
||||
t.Fatalf("wanted %v, but got %v", tc.expectResult, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDayOfMonthRange_Validate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
in DayOfMonthRange
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test zero value returns error",
|
||||
in: DayOfMonthRange{
|
||||
Start: 0,
|
||||
End: 0,
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test out of range returns error",
|
||||
in: DayOfMonthRange{
|
||||
Start: -50,
|
||||
End: -20,
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test out of range returns error",
|
||||
in: DayOfMonthRange{
|
||||
Start: 20,
|
||||
End: 50,
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid input - negative start day with positive end day",
|
||||
in: DayOfMonthRange{
|
||||
Start: -20,
|
||||
End: 5,
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid range - end before start returns error",
|
||||
in: DayOfMonthRange{
|
||||
Start: 10,
|
||||
End: -25,
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
in: DayOfMonthRange{
|
||||
Start: 1,
|
||||
End: 31,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := tc.in.Validate()
|
||||
if tc.expectErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected err but got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error but got %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestYearRange_Parse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
in YearRange
|
||||
expectErr bool
|
||||
expectResult *ParsedRange
|
||||
}{
|
||||
{
|
||||
name: "Test invalid range - more than two years returns an error",
|
||||
in: YearRange("2019:2029:2039"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test invalid range - end before start returns error",
|
||||
in: YearRange("2020:2010"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Test happy path",
|
||||
in: YearRange("2030"),
|
||||
expectResult: &ParsedRange{
|
||||
Start: 2030,
|
||||
End: 2030,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test happy path range",
|
||||
in: YearRange("2030:2050"),
|
||||
expectResult: &ParsedRange{
|
||||
Start: 2030,
|
||||
End: 2050,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got, err := tc.in.Parse()
|
||||
if tc.expectErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected err but got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error but got %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.expectResult) {
|
||||
t.Fatalf("wanted %v, but got %v", tc.expectResult, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
937
pkg/apis/monitoring/v1beta1/zz_generated.deepcopy.go
generated
Normal file
937
pkg/apis/monitoring/v1beta1/zz_generated.deepcopy.go
generated
Normal file
|
@ -0,0 +1,937 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AlertmanagerConfig) DeepCopyInto(out *AlertmanagerConfig) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlertmanagerConfig.
|
||||
func (in *AlertmanagerConfig) DeepCopy() *AlertmanagerConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AlertmanagerConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AlertmanagerConfigList) DeepCopyInto(out *AlertmanagerConfigList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]*AlertmanagerConfig, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(AlertmanagerConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlertmanagerConfigList.
|
||||
func (in *AlertmanagerConfigList) DeepCopy() *AlertmanagerConfigList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AlertmanagerConfigList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AlertmanagerConfigSpec) DeepCopyInto(out *AlertmanagerConfigSpec) {
|
||||
*out = *in
|
||||
if in.Route != nil {
|
||||
in, out := &in.Route, &out.Route
|
||||
*out = new(Route)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Receivers != nil {
|
||||
in, out := &in.Receivers, &out.Receivers
|
||||
*out = make([]Receiver, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.InhibitRules != nil {
|
||||
in, out := &in.InhibitRules, &out.InhibitRules
|
||||
*out = make([]InhibitRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.TimeIntervals != nil {
|
||||
in, out := &in.TimeIntervals, &out.TimeIntervals
|
||||
*out = make([]TimeInterval, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AlertmanagerConfigSpec.
|
||||
func (in *AlertmanagerConfigSpec) DeepCopy() *AlertmanagerConfigSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AlertmanagerConfigSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DayOfMonthRange) DeepCopyInto(out *DayOfMonthRange) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DayOfMonthRange.
|
||||
func (in *DayOfMonthRange) DeepCopy() *DayOfMonthRange {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DayOfMonthRange)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *EmailConfig) DeepCopyInto(out *EmailConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.AuthPassword != nil {
|
||||
in, out := &in.AuthPassword, &out.AuthPassword
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.AuthSecret != nil {
|
||||
in, out := &in.AuthSecret, &out.AuthSecret
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.Headers != nil {
|
||||
in, out := &in.Headers, &out.Headers
|
||||
*out = make([]KeyValue, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RequireTLS != nil {
|
||||
in, out := &in.RequireTLS, &out.RequireTLS
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.TLSConfig != nil {
|
||||
in, out := &in.TLSConfig, &out.TLSConfig
|
||||
*out = new(monitoringv1.SafeTLSConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmailConfig.
|
||||
func (in *EmailConfig) DeepCopy() *EmailConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(EmailConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTPConfig) DeepCopyInto(out *HTTPConfig) {
|
||||
*out = *in
|
||||
if in.Authorization != nil {
|
||||
in, out := &in.Authorization, &out.Authorization
|
||||
*out = new(monitoringv1.SafeAuthorization)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.BasicAuth != nil {
|
||||
in, out := &in.BasicAuth, &out.BasicAuth
|
||||
*out = new(monitoringv1.BasicAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.OAuth2 != nil {
|
||||
in, out := &in.OAuth2, &out.OAuth2
|
||||
*out = new(monitoringv1.OAuth2)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.BearerTokenSecret != nil {
|
||||
in, out := &in.BearerTokenSecret, &out.BearerTokenSecret
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.TLSConfig != nil {
|
||||
in, out := &in.TLSConfig, &out.TLSConfig
|
||||
*out = new(monitoringv1.SafeTLSConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.FollowRedirects != nil {
|
||||
in, out := &in.FollowRedirects, &out.FollowRedirects
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPConfig.
|
||||
func (in *HTTPConfig) DeepCopy() *HTTPConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HTTPConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *InhibitRule) DeepCopyInto(out *InhibitRule) {
|
||||
*out = *in
|
||||
if in.TargetMatch != nil {
|
||||
in, out := &in.TargetMatch, &out.TargetMatch
|
||||
*out = make([]Matcher, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.SourceMatch != nil {
|
||||
in, out := &in.SourceMatch, &out.SourceMatch
|
||||
*out = make([]Matcher, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Equal != nil {
|
||||
in, out := &in.Equal, &out.Equal
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InhibitRule.
|
||||
func (in *InhibitRule) DeepCopy() *InhibitRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(InhibitRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KeyValue) DeepCopyInto(out *KeyValue) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyValue.
|
||||
func (in *KeyValue) DeepCopy() *KeyValue {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KeyValue)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Matcher) DeepCopyInto(out *Matcher) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Matcher.
|
||||
func (in *Matcher) DeepCopy() *Matcher {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Matcher)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *OpsGenieConfig) DeepCopyInto(out *OpsGenieConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.APIKey != nil {
|
||||
in, out := &in.APIKey, &out.APIKey
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.Details != nil {
|
||||
in, out := &in.Details, &out.Details
|
||||
*out = make([]KeyValue, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Responders != nil {
|
||||
in, out := &in.Responders, &out.Responders
|
||||
*out = make([]OpsGenieConfigResponder, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpsGenieConfig.
|
||||
func (in *OpsGenieConfig) DeepCopy() *OpsGenieConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(OpsGenieConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *OpsGenieConfigResponder) DeepCopyInto(out *OpsGenieConfigResponder) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpsGenieConfigResponder.
|
||||
func (in *OpsGenieConfigResponder) DeepCopy() *OpsGenieConfigResponder {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(OpsGenieConfigResponder)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PagerDutyConfig) DeepCopyInto(out *PagerDutyConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.RoutingKey != nil {
|
||||
in, out := &in.RoutingKey, &out.RoutingKey
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.ServiceKey != nil {
|
||||
in, out := &in.ServiceKey, &out.ServiceKey
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.Details != nil {
|
||||
in, out := &in.Details, &out.Details
|
||||
*out = make([]KeyValue, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.PagerDutyImageConfigs != nil {
|
||||
in, out := &in.PagerDutyImageConfigs, &out.PagerDutyImageConfigs
|
||||
*out = make([]PagerDutyImageConfig, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.PagerDutyLinkConfigs != nil {
|
||||
in, out := &in.PagerDutyLinkConfigs, &out.PagerDutyLinkConfigs
|
||||
*out = make([]PagerDutyLinkConfig, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PagerDutyConfig.
|
||||
func (in *PagerDutyConfig) DeepCopy() *PagerDutyConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PagerDutyConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PagerDutyImageConfig) DeepCopyInto(out *PagerDutyImageConfig) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PagerDutyImageConfig.
|
||||
func (in *PagerDutyImageConfig) DeepCopy() *PagerDutyImageConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PagerDutyImageConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PagerDutyLinkConfig) DeepCopyInto(out *PagerDutyLinkConfig) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PagerDutyLinkConfig.
|
||||
func (in *PagerDutyLinkConfig) DeepCopy() *PagerDutyLinkConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PagerDutyLinkConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PushoverConfig) DeepCopyInto(out *PushoverConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.UserKey != nil {
|
||||
in, out := &in.UserKey, &out.UserKey
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.Token != nil {
|
||||
in, out := &in.Token, &out.Token
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PushoverConfig.
|
||||
func (in *PushoverConfig) DeepCopy() *PushoverConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PushoverConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Receiver) DeepCopyInto(out *Receiver) {
|
||||
*out = *in
|
||||
if in.OpsGenieConfigs != nil {
|
||||
in, out := &in.OpsGenieConfigs, &out.OpsGenieConfigs
|
||||
*out = make([]OpsGenieConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.PagerDutyConfigs != nil {
|
||||
in, out := &in.PagerDutyConfigs, &out.PagerDutyConfigs
|
||||
*out = make([]PagerDutyConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.SlackConfigs != nil {
|
||||
in, out := &in.SlackConfigs, &out.SlackConfigs
|
||||
*out = make([]SlackConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.WebhookConfigs != nil {
|
||||
in, out := &in.WebhookConfigs, &out.WebhookConfigs
|
||||
*out = make([]WebhookConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.WeChatConfigs != nil {
|
||||
in, out := &in.WeChatConfigs, &out.WeChatConfigs
|
||||
*out = make([]WeChatConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.EmailConfigs != nil {
|
||||
in, out := &in.EmailConfigs, &out.EmailConfigs
|
||||
*out = make([]EmailConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.VictorOpsConfigs != nil {
|
||||
in, out := &in.VictorOpsConfigs, &out.VictorOpsConfigs
|
||||
*out = make([]VictorOpsConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.PushoverConfigs != nil {
|
||||
in, out := &in.PushoverConfigs, &out.PushoverConfigs
|
||||
*out = make([]PushoverConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.SNSConfigs != nil {
|
||||
in, out := &in.SNSConfigs, &out.SNSConfigs
|
||||
*out = make([]SNSConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.TelegramConfigs != nil {
|
||||
in, out := &in.TelegramConfigs, &out.TelegramConfigs
|
||||
*out = make([]TelegramConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Receiver.
|
||||
func (in *Receiver) DeepCopy() *Receiver {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Receiver)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Route) DeepCopyInto(out *Route) {
|
||||
*out = *in
|
||||
if in.GroupBy != nil {
|
||||
in, out := &in.GroupBy, &out.GroupBy
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Matchers != nil {
|
||||
in, out := &in.Matchers, &out.Matchers
|
||||
*out = make([]Matcher, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Routes != nil {
|
||||
in, out := &in.Routes, &out.Routes
|
||||
*out = make([]v1.JSON, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.MuteTimeIntervals != nil {
|
||||
in, out := &in.MuteTimeIntervals, &out.MuteTimeIntervals
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route.
|
||||
func (in *Route) DeepCopy() *Route {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Route)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SNSConfig) DeepCopyInto(out *SNSConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.Sigv4 != nil {
|
||||
in, out := &in.Sigv4, &out.Sigv4
|
||||
*out = new(monitoringv1.Sigv4)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Attributes != nil {
|
||||
in, out := &in.Attributes, &out.Attributes
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SNSConfig.
|
||||
func (in *SNSConfig) DeepCopy() *SNSConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SNSConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.
|
||||
func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SecretKeySelector)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SlackAction) DeepCopyInto(out *SlackAction) {
|
||||
*out = *in
|
||||
if in.ConfirmField != nil {
|
||||
in, out := &in.ConfirmField, &out.ConfirmField
|
||||
*out = new(SlackConfirmationField)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlackAction.
|
||||
func (in *SlackAction) DeepCopy() *SlackAction {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SlackAction)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SlackConfig) DeepCopyInto(out *SlackConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.APIURL != nil {
|
||||
in, out := &in.APIURL, &out.APIURL
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.Fields != nil {
|
||||
in, out := &in.Fields, &out.Fields
|
||||
*out = make([]SlackField, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.MrkdwnIn != nil {
|
||||
in, out := &in.MrkdwnIn, &out.MrkdwnIn
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Actions != nil {
|
||||
in, out := &in.Actions, &out.Actions
|
||||
*out = make([]SlackAction, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlackConfig.
|
||||
func (in *SlackConfig) DeepCopy() *SlackConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SlackConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SlackConfirmationField) DeepCopyInto(out *SlackConfirmationField) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlackConfirmationField.
|
||||
func (in *SlackConfirmationField) DeepCopy() *SlackConfirmationField {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SlackConfirmationField)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SlackField) DeepCopyInto(out *SlackField) {
|
||||
*out = *in
|
||||
if in.Short != nil {
|
||||
in, out := &in.Short, &out.Short
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SlackField.
|
||||
func (in *SlackField) DeepCopy() *SlackField {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SlackField)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TelegramConfig) DeepCopyInto(out *TelegramConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.BotToken != nil {
|
||||
in, out := &in.BotToken, &out.BotToken
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.DisableNotifications != nil {
|
||||
in, out := &in.DisableNotifications, &out.DisableNotifications
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TelegramConfig.
|
||||
func (in *TelegramConfig) DeepCopy() *TelegramConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TelegramConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TimeInterval) DeepCopyInto(out *TimeInterval) {
|
||||
*out = *in
|
||||
if in.TimeIntervals != nil {
|
||||
in, out := &in.TimeIntervals, &out.TimeIntervals
|
||||
*out = make([]TimePeriod, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeInterval.
|
||||
func (in *TimeInterval) DeepCopy() *TimeInterval {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TimeInterval)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TimePeriod) DeepCopyInto(out *TimePeriod) {
|
||||
*out = *in
|
||||
if in.Times != nil {
|
||||
in, out := &in.Times, &out.Times
|
||||
*out = make([]TimeRange, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Weekdays != nil {
|
||||
in, out := &in.Weekdays, &out.Weekdays
|
||||
*out = make([]WeekdayRange, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.DaysOfMonth != nil {
|
||||
in, out := &in.DaysOfMonth, &out.DaysOfMonth
|
||||
*out = make([]DayOfMonthRange, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Months != nil {
|
||||
in, out := &in.Months, &out.Months
|
||||
*out = make([]MonthRange, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Years != nil {
|
||||
in, out := &in.Years, &out.Years
|
||||
*out = make([]YearRange, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimePeriod.
|
||||
func (in *TimePeriod) DeepCopy() *TimePeriod {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TimePeriod)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TimeRange) DeepCopyInto(out *TimeRange) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeRange.
|
||||
func (in *TimeRange) DeepCopy() *TimeRange {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TimeRange)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *VictorOpsConfig) DeepCopyInto(out *VictorOpsConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.APIKey != nil {
|
||||
in, out := &in.APIKey, &out.APIKey
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.CustomFields != nil {
|
||||
in, out := &in.CustomFields, &out.CustomFields
|
||||
*out = make([]KeyValue, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VictorOpsConfig.
|
||||
func (in *VictorOpsConfig) DeepCopy() *VictorOpsConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(VictorOpsConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WeChatConfig) DeepCopyInto(out *WeChatConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.APISecret != nil {
|
||||
in, out := &in.APISecret, &out.APISecret
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WeChatConfig.
|
||||
func (in *WeChatConfig) DeepCopy() *WeChatConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(WeChatConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookConfig) DeepCopyInto(out *WebhookConfig) {
|
||||
*out = *in
|
||||
if in.SendResolved != nil {
|
||||
in, out := &in.SendResolved, &out.SendResolved
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.URL != nil {
|
||||
in, out := &in.URL, &out.URL
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.URLSecret != nil {
|
||||
in, out := &in.URLSecret, &out.URLSecret
|
||||
*out = new(SecretKeySelector)
|
||||
**out = **in
|
||||
}
|
||||
if in.HTTPConfig != nil {
|
||||
in, out := &in.HTTPConfig, &out.HTTPConfig
|
||||
*out = new(HTTPConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConfig.
|
||||
func (in *WebhookConfig) DeepCopy() *WebhookConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(WebhookConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
|
@ -21,6 +21,7 @@ import (
|
|||
|
||||
v1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
v1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
v1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
@ -71,6 +72,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
|||
case v1alpha1.SchemeGroupVersion.WithResource("alertmanagerconfigs"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Monitoring().V1alpha1().AlertmanagerConfigs().Informer()}, nil
|
||||
|
||||
// Group=monitoring.coreos.com, Version=v1beta1
|
||||
case v1beta1.SchemeGroupVersion.WithResource("alertmanagerconfigs"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Monitoring().V1beta1().AlertmanagerConfigs().Informer()}, nil
|
||||
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no informer found for %v", resource)
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
internalinterfaces "github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions/internalinterfaces"
|
||||
v1 "github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions/monitoring/v1"
|
||||
v1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions/monitoring/v1alpha1"
|
||||
v1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions/monitoring/v1beta1"
|
||||
)
|
||||
|
||||
// Interface provides access to each of this group's versions.
|
||||
|
@ -28,6 +29,8 @@ type Interface interface {
|
|||
V1() v1.Interface
|
||||
// V1alpha1 provides access to shared informers for resources in V1alpha1.
|
||||
V1alpha1() v1alpha1.Interface
|
||||
// V1beta1 provides access to shared informers for resources in V1beta1.
|
||||
V1beta1() v1beta1.Interface
|
||||
}
|
||||
|
||||
type group struct {
|
||||
|
@ -50,3 +53,8 @@ func (g *group) V1() v1.Interface {
|
|||
func (g *group) V1alpha1() v1alpha1.Interface {
|
||||
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
|
||||
// V1beta1 returns a new v1beta1.Interface.
|
||||
func (g *group) V1beta1() v1beta1.Interface {
|
||||
return v1beta1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"context"
|
||||
time "time"
|
||||
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
internalinterfaces "github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions/internalinterfaces"
|
||||
v1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/client/listers/monitoring/v1beta1"
|
||||
versioned "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// AlertmanagerConfigInformer provides access to a shared informer and lister for
|
||||
// AlertmanagerConfigs.
|
||||
type AlertmanagerConfigInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1beta1.AlertmanagerConfigLister
|
||||
}
|
||||
|
||||
type alertmanagerConfigInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewAlertmanagerConfigInformer constructs a new informer for AlertmanagerConfig type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewAlertmanagerConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredAlertmanagerConfigInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredAlertmanagerConfigInformer constructs a new informer for AlertmanagerConfig type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredAlertmanagerConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).List(context.TODO(), options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.MonitoringV1beta1().AlertmanagerConfigs(namespace).Watch(context.TODO(), options)
|
||||
},
|
||||
},
|
||||
&monitoringv1beta1.AlertmanagerConfig{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *alertmanagerConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredAlertmanagerConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *alertmanagerConfigInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&monitoringv1beta1.AlertmanagerConfig{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *alertmanagerConfigInformer) Lister() v1beta1.AlertmanagerConfigLister {
|
||||
return v1beta1.NewAlertmanagerConfigLister(f.Informer().GetIndexer())
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
internalinterfaces "github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// AlertmanagerConfigs returns a AlertmanagerConfigInformer.
|
||||
AlertmanagerConfigs() AlertmanagerConfigInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// AlertmanagerConfigs returns a AlertmanagerConfigInformer.
|
||||
func (v *version) AlertmanagerConfigs() AlertmanagerConfigInformer {
|
||||
return &alertmanagerConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
97
pkg/client/listers/monitoring/v1beta1/alertmanagerconfig.go
Normal file
97
pkg/client/listers/monitoring/v1beta1/alertmanagerconfig.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
v1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// AlertmanagerConfigLister helps list AlertmanagerConfigs.
|
||||
// All objects returned here must be treated as read-only.
|
||||
type AlertmanagerConfigLister interface {
|
||||
// List lists all AlertmanagerConfigs in the indexer.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*v1beta1.AlertmanagerConfig, err error)
|
||||
// AlertmanagerConfigs returns an object that can list and get AlertmanagerConfigs.
|
||||
AlertmanagerConfigs(namespace string) AlertmanagerConfigNamespaceLister
|
||||
AlertmanagerConfigListerExpansion
|
||||
}
|
||||
|
||||
// alertmanagerConfigLister implements the AlertmanagerConfigLister interface.
|
||||
type alertmanagerConfigLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewAlertmanagerConfigLister returns a new AlertmanagerConfigLister.
|
||||
func NewAlertmanagerConfigLister(indexer cache.Indexer) AlertmanagerConfigLister {
|
||||
return &alertmanagerConfigLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all AlertmanagerConfigs in the indexer.
|
||||
func (s *alertmanagerConfigLister) List(selector labels.Selector) (ret []*v1beta1.AlertmanagerConfig, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1beta1.AlertmanagerConfig))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// AlertmanagerConfigs returns an object that can list and get AlertmanagerConfigs.
|
||||
func (s *alertmanagerConfigLister) AlertmanagerConfigs(namespace string) AlertmanagerConfigNamespaceLister {
|
||||
return alertmanagerConfigNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// AlertmanagerConfigNamespaceLister helps list and get AlertmanagerConfigs.
|
||||
// All objects returned here must be treated as read-only.
|
||||
type AlertmanagerConfigNamespaceLister interface {
|
||||
// List lists all AlertmanagerConfigs in the indexer for a given namespace.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*v1beta1.AlertmanagerConfig, err error)
|
||||
// Get retrieves the AlertmanagerConfig from the indexer for a given namespace and name.
|
||||
// Objects returned here must be treated as read-only.
|
||||
Get(name string) (*v1beta1.AlertmanagerConfig, error)
|
||||
AlertmanagerConfigNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// alertmanagerConfigNamespaceLister implements the AlertmanagerConfigNamespaceLister
|
||||
// interface.
|
||||
type alertmanagerConfigNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all AlertmanagerConfigs in the indexer for a given namespace.
|
||||
func (s alertmanagerConfigNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.AlertmanagerConfig, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1beta1.AlertmanagerConfig))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the AlertmanagerConfig from the indexer for a given namespace and name.
|
||||
func (s alertmanagerConfigNamespaceLister) Get(name string) (*v1beta1.AlertmanagerConfig, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1beta1.Resource("alertmanagerconfig"), name)
|
||||
}
|
||||
return obj.(*v1beta1.AlertmanagerConfig), nil
|
||||
}
|
25
pkg/client/listers/monitoring/v1beta1/expansion_generated.go
Normal file
25
pkg/client/listers/monitoring/v1beta1/expansion_generated.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
// AlertmanagerConfigListerExpansion allows custom methods to be added to
|
||||
// AlertmanagerConfigLister.
|
||||
type AlertmanagerConfigListerExpansion interface{}
|
||||
|
||||
// AlertmanagerConfigNamespaceListerExpansion allows custom methods to be added to
|
||||
// AlertmanagerConfigNamespaceLister.
|
||||
type AlertmanagerConfigNamespaceListerExpansion interface{}
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1alpha1"
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1beta1"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
|
@ -31,6 +32,7 @@ type Interface interface {
|
|||
Discovery() discovery.DiscoveryInterface
|
||||
MonitoringV1() monitoringv1.MonitoringV1Interface
|
||||
MonitoringV1alpha1() monitoringv1alpha1.MonitoringV1alpha1Interface
|
||||
MonitoringV1beta1() monitoringv1beta1.MonitoringV1beta1Interface
|
||||
}
|
||||
|
||||
// Clientset contains the clients for groups. Each group has exactly one
|
||||
|
@ -39,6 +41,7 @@ type Clientset struct {
|
|||
*discovery.DiscoveryClient
|
||||
monitoringV1 *monitoringv1.MonitoringV1Client
|
||||
monitoringV1alpha1 *monitoringv1alpha1.MonitoringV1alpha1Client
|
||||
monitoringV1beta1 *monitoringv1beta1.MonitoringV1beta1Client
|
||||
}
|
||||
|
||||
// MonitoringV1 retrieves the MonitoringV1Client
|
||||
|
@ -51,6 +54,11 @@ func (c *Clientset) MonitoringV1alpha1() monitoringv1alpha1.MonitoringV1alpha1In
|
|||
return c.monitoringV1alpha1
|
||||
}
|
||||
|
||||
// MonitoringV1beta1 retrieves the MonitoringV1beta1Client
|
||||
func (c *Clientset) MonitoringV1beta1() monitoringv1beta1.MonitoringV1beta1Interface {
|
||||
return c.monitoringV1beta1
|
||||
}
|
||||
|
||||
// Discovery retrieves the DiscoveryClient
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
if c == nil {
|
||||
|
@ -99,6 +107,10 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.monitoringV1beta1, err = monitoringv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient)
|
||||
if err != nil {
|
||||
|
@ -122,6 +134,7 @@ func New(c rest.Interface) *Clientset {
|
|||
var cs Clientset
|
||||
cs.monitoringV1 = monitoringv1.New(c)
|
||||
cs.monitoringV1alpha1 = monitoringv1alpha1.New(c)
|
||||
cs.monitoringV1beta1 = monitoringv1beta1.New(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
|
||||
return &cs
|
||||
|
|
|
@ -22,6 +22,8 @@ import (
|
|||
fakemonitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1/fake"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1alpha1"
|
||||
fakemonitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1alpha1/fake"
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1beta1"
|
||||
fakemonitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1beta1/fake"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
|
@ -88,3 +90,8 @@ func (c *Clientset) MonitoringV1() monitoringv1.MonitoringV1Interface {
|
|||
func (c *Clientset) MonitoringV1alpha1() monitoringv1alpha1.MonitoringV1alpha1Interface {
|
||||
return &fakemonitoringv1alpha1.FakeMonitoringV1alpha1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// MonitoringV1beta1 retrieves the MonitoringV1beta1Client
|
||||
func (c *Clientset) MonitoringV1beta1() monitoringv1beta1.MonitoringV1beta1Interface {
|
||||
return &fakemonitoringv1beta1.FakeMonitoringV1beta1{Fake: &c.Fake}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package fake
|
|||
import (
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
@ -32,6 +33,7 @@ var codecs = serializer.NewCodecFactory(scheme)
|
|||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
monitoringv1.AddToScheme,
|
||||
monitoringv1alpha1.AddToScheme,
|
||||
monitoringv1beta1.AddToScheme,
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
|
|
|
@ -19,6 +19,7 @@ package scheme
|
|||
import (
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
@ -32,6 +33,7 @@ var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
|||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
monitoringv1.AddToScheme,
|
||||
monitoringv1alpha1.AddToScheme,
|
||||
monitoringv1beta1.AddToScheme,
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
scheme "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/scheme"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// AlertmanagerConfigsGetter has a method to return a AlertmanagerConfigInterface.
|
||||
// A group's client should implement this interface.
|
||||
type AlertmanagerConfigsGetter interface {
|
||||
AlertmanagerConfigs(namespace string) AlertmanagerConfigInterface
|
||||
}
|
||||
|
||||
// AlertmanagerConfigInterface has methods to work with AlertmanagerConfig resources.
|
||||
type AlertmanagerConfigInterface interface {
|
||||
Create(ctx context.Context, alertmanagerConfig *v1beta1.AlertmanagerConfig, opts v1.CreateOptions) (*v1beta1.AlertmanagerConfig, error)
|
||||
Update(ctx context.Context, alertmanagerConfig *v1beta1.AlertmanagerConfig, opts v1.UpdateOptions) (*v1beta1.AlertmanagerConfig, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.AlertmanagerConfig, error)
|
||||
List(ctx context.Context, opts v1.ListOptions) (*v1beta1.AlertmanagerConfigList, error)
|
||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.AlertmanagerConfig, err error)
|
||||
AlertmanagerConfigExpansion
|
||||
}
|
||||
|
||||
// alertmanagerConfigs implements AlertmanagerConfigInterface
|
||||
type alertmanagerConfigs struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newAlertmanagerConfigs returns a AlertmanagerConfigs
|
||||
func newAlertmanagerConfigs(c *MonitoringV1beta1Client, namespace string) *alertmanagerConfigs {
|
||||
return &alertmanagerConfigs{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the alertmanagerConfig, and returns the corresponding alertmanagerConfig object, and an error if there is any.
|
||||
func (c *alertmanagerConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.AlertmanagerConfig, err error) {
|
||||
result = &v1beta1.AlertmanagerConfig{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("alertmanagerconfigs").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of AlertmanagerConfigs that match those selectors.
|
||||
func (c *alertmanagerConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.AlertmanagerConfigList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1beta1.AlertmanagerConfigList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("alertmanagerconfigs").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested alertmanagerConfigs.
|
||||
func (c *alertmanagerConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("alertmanagerconfigs").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch(ctx)
|
||||
}
|
||||
|
||||
// Create takes the representation of a alertmanagerConfig and creates it. Returns the server's representation of the alertmanagerConfig, and an error, if there is any.
|
||||
func (c *alertmanagerConfigs) Create(ctx context.Context, alertmanagerConfig *v1beta1.AlertmanagerConfig, opts v1.CreateOptions) (result *v1beta1.AlertmanagerConfig, err error) {
|
||||
result = &v1beta1.AlertmanagerConfig{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("alertmanagerconfigs").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(alertmanagerConfig).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a alertmanagerConfig and updates it. Returns the server's representation of the alertmanagerConfig, and an error, if there is any.
|
||||
func (c *alertmanagerConfigs) Update(ctx context.Context, alertmanagerConfig *v1beta1.AlertmanagerConfig, opts v1.UpdateOptions) (result *v1beta1.AlertmanagerConfig, err error) {
|
||||
result = &v1beta1.AlertmanagerConfig{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("alertmanagerconfigs").
|
||||
Name(alertmanagerConfig.Name).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(alertmanagerConfig).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the alertmanagerConfig and deletes it. Returns an error if one occurs.
|
||||
func (c *alertmanagerConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("alertmanagerconfigs").
|
||||
Name(name).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *alertmanagerConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOpts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("alertmanagerconfigs").
|
||||
VersionedParams(&listOpts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched alertmanagerConfig.
|
||||
func (c *alertmanagerConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.AlertmanagerConfig, err error) {
|
||||
result = &v1beta1.AlertmanagerConfig{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("alertmanagerconfigs").
|
||||
Name(name).
|
||||
SubResource(subresources...).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(data).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
18
pkg/client/versioned/typed/monitoring/v1beta1/doc.go
Normal file
18
pkg/client/versioned/typed/monitoring/v1beta1/doc.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1beta1
|
18
pkg/client/versioned/typed/monitoring/v1beta1/fake/doc.go
Normal file
18
pkg/client/versioned/typed/monitoring/v1beta1/fake/doc.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
v1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeAlertmanagerConfigs implements AlertmanagerConfigInterface
|
||||
type FakeAlertmanagerConfigs struct {
|
||||
Fake *FakeMonitoringV1beta1
|
||||
ns string
|
||||
}
|
||||
|
||||
var alertmanagerconfigsResource = schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1beta1", Resource: "alertmanagerconfigs"}
|
||||
|
||||
var alertmanagerconfigsKind = schema.GroupVersionKind{Group: "monitoring.coreos.com", Version: "v1beta1", Kind: "AlertmanagerConfig"}
|
||||
|
||||
// Get takes name of the alertmanagerConfig, and returns the corresponding alertmanagerConfig object, and an error if there is any.
|
||||
func (c *FakeAlertmanagerConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.AlertmanagerConfig, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(alertmanagerconfigsResource, c.ns, name), &v1beta1.AlertmanagerConfig{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.AlertmanagerConfig), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of AlertmanagerConfigs that match those selectors.
|
||||
func (c *FakeAlertmanagerConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.AlertmanagerConfigList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(alertmanagerconfigsResource, alertmanagerconfigsKind, c.ns, opts), &v1beta1.AlertmanagerConfigList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1beta1.AlertmanagerConfigList{ListMeta: obj.(*v1beta1.AlertmanagerConfigList).ListMeta}
|
||||
for _, item := range obj.(*v1beta1.AlertmanagerConfigList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested alertmanagerConfigs.
|
||||
func (c *FakeAlertmanagerConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(alertmanagerconfigsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a alertmanagerConfig and creates it. Returns the server's representation of the alertmanagerConfig, and an error, if there is any.
|
||||
func (c *FakeAlertmanagerConfigs) Create(ctx context.Context, alertmanagerConfig *v1beta1.AlertmanagerConfig, opts v1.CreateOptions) (result *v1beta1.AlertmanagerConfig, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(alertmanagerconfigsResource, c.ns, alertmanagerConfig), &v1beta1.AlertmanagerConfig{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.AlertmanagerConfig), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a alertmanagerConfig and updates it. Returns the server's representation of the alertmanagerConfig, and an error, if there is any.
|
||||
func (c *FakeAlertmanagerConfigs) Update(ctx context.Context, alertmanagerConfig *v1beta1.AlertmanagerConfig, opts v1.UpdateOptions) (result *v1beta1.AlertmanagerConfig, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(alertmanagerconfigsResource, c.ns, alertmanagerConfig), &v1beta1.AlertmanagerConfig{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.AlertmanagerConfig), err
|
||||
}
|
||||
|
||||
// Delete takes name of the alertmanagerConfig and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeAlertmanagerConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteActionWithOptions(alertmanagerconfigsResource, c.ns, name, opts), &v1beta1.AlertmanagerConfig{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeAlertmanagerConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(alertmanagerconfigsResource, c.ns, listOpts)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1beta1.AlertmanagerConfigList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched alertmanagerConfig.
|
||||
func (c *FakeAlertmanagerConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.AlertmanagerConfig, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(alertmanagerconfigsResource, c.ns, name, pt, data, subresources...), &v1beta1.AlertmanagerConfig{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.AlertmanagerConfig), err
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1beta1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
type FakeMonitoringV1beta1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeMonitoringV1beta1) AlertmanagerConfigs(namespace string) v1beta1.AlertmanagerConfigInterface {
|
||||
return &FakeAlertmanagerConfigs{c, namespace}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeMonitoringV1beta1) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
type AlertmanagerConfigExpansion interface{}
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright The prometheus-operator Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
v1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
"github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type MonitoringV1beta1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
AlertmanagerConfigsGetter
|
||||
}
|
||||
|
||||
// MonitoringV1beta1Client is used to interact with features provided by the monitoring.coreos.com group.
|
||||
type MonitoringV1beta1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *MonitoringV1beta1Client) AlertmanagerConfigs(namespace string) AlertmanagerConfigInterface {
|
||||
return newAlertmanagerConfigs(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new MonitoringV1beta1Client for the given config.
|
||||
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
|
||||
// where httpClient was generated with rest.HTTPClientFor(c).
|
||||
func NewForConfig(c *rest.Config) (*MonitoringV1beta1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpClient, err := rest.HTTPClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewForConfigAndClient(&config, httpClient)
|
||||
}
|
||||
|
||||
// NewForConfigAndClient creates a new MonitoringV1beta1Client for the given config and http client.
|
||||
// Note the http client provided takes precedence over the configured transport values.
|
||||
func NewForConfigAndClient(c *rest.Config, h *http.Client) (*MonitoringV1beta1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientForConfigAndClient(&config, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &MonitoringV1beta1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new MonitoringV1beta1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *MonitoringV1beta1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new MonitoringV1beta1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *MonitoringV1beta1Client {
|
||||
return &MonitoringV1beta1Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1beta1.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *MonitoringV1beta1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
10
scripts/generate/build-conversion-webhook-patch-for-alermanagerconfig-crd.sh
Executable file
10
scripts/generate/build-conversion-webhook-patch-for-alermanagerconfig-crd.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
# exit immediately when a command fails
|
||||
set -e
|
||||
# only exit with zero if all commands of the pipeline exit successfully
|
||||
set -o pipefail
|
||||
# error on unset variables
|
||||
set -u
|
||||
|
||||
jsonnet -J scripts/generate/vendor scripts/generate/conversion-webhook-patch-for-alermanagerconfig-crd.jsonnet > "example/alertmanager-crd-conversion/patch.json"
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Create JSON patch that configures the conversion webhook for the Alertmanager CRD.
|
||||
local alertmanagerConfigCrd = (import 'prometheus-operator/alertmanagerconfigs-crd.json');
|
||||
local conversion = (import 'prometheus-operator/conversion.libsonnet');
|
||||
local admissionWebhook = (import 'prometheus-operator/admission-webhook.libsonnet');
|
||||
local config = (import 'config.jsonnet');
|
||||
|
||||
local aw = admissionWebhook(config {
|
||||
image: 'quay.io/prometheus-operator/admission-webhook:v' + config.version,
|
||||
});
|
||||
|
||||
{
|
||||
apiVersion: alertmanagerConfigCrd.apiVersion,
|
||||
kind: alertmanagerConfigCrd.kind,
|
||||
metadata: alertmanagerConfigCrd.metadata,
|
||||
} + conversion({
|
||||
name: aw.service.metadata.name,
|
||||
namespace: aw.service.metadata.namespace,
|
||||
})
|
|
@ -17,6 +17,7 @@ package e2e
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -38,6 +39,7 @@ import (
|
|||
"github.com/prometheus-operator/prometheus-operator/pkg/alertmanager"
|
||||
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
monitoringv1beta1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1beta1"
|
||||
)
|
||||
|
||||
func testAMCreateDeleteCluster(t *testing.T) {
|
||||
|
@ -712,6 +714,82 @@ inhibit_rules:
|
|||
}
|
||||
}
|
||||
|
||||
func testAlertmanagerConfigVersions(t *testing.T) {
|
||||
// Don't run Alertmanager tests in parallel. See
|
||||
// https://github.com/prometheus/alertmanager/issues/1835 for details.
|
||||
testCtx := framework.NewTestCtx(t)
|
||||
defer testCtx.Cleanup(t)
|
||||
ns := framework.CreateNamespace(context.Background(), t, testCtx)
|
||||
framework.SetupPrometheusRBAC(context.Background(), t, testCtx, ns)
|
||||
|
||||
alertmanager := framework.MakeBasicAlertmanager("amconfig-versions", 1)
|
||||
alertmanager.Spec.AlertmanagerConfigSelector = &metav1.LabelSelector{}
|
||||
alertmanager, err := framework.CreateAlertmanagerAndWaitUntilReady(context.Background(), ns, alertmanager)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
amcfgV1alpha1 := &monitoringv1alpha1.AlertmanagerConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "amcfg-v1alpha1",
|
||||
},
|
||||
Spec: monitoringv1alpha1.AlertmanagerConfigSpec{
|
||||
Route: &monitoringv1alpha1.Route{
|
||||
Receiver: "webhook",
|
||||
Matchers: []monitoringv1alpha1.Matcher{{
|
||||
Name: "job",
|
||||
Value: "webapp.+",
|
||||
Regex: true,
|
||||
}},
|
||||
},
|
||||
Receivers: []monitoringv1alpha1.Receiver{{
|
||||
Name: "webhook",
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := framework.MonClientV1alpha1.AlertmanagerConfigs(alertmanager.Namespace).Create(context.Background(), amcfgV1alpha1, metav1.CreateOptions{}); err != nil {
|
||||
t.Fatalf("failed to create v1alpha1 AlertmanagerConfig object: %v", err)
|
||||
}
|
||||
|
||||
amcfgV1beta1Converted, err := framework.MonClientV1beta1.AlertmanagerConfigs(alertmanager.Namespace).Get(context.Background(), amcfgV1alpha1.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get v1beta1 AlertmanagerConfig object: %v", err)
|
||||
}
|
||||
|
||||
expected := []monitoringv1beta1.Matcher{{Name: "job", Value: "webapp.+", MatchType: monitoringv1beta1.MatchRegexp}}
|
||||
if !reflect.DeepEqual(amcfgV1beta1Converted.Spec.Route.Matchers, expected) {
|
||||
t.Fatalf("expected %#v matcher, got %#v", expected, amcfgV1beta1Converted.Spec.Route.Matchers)
|
||||
}
|
||||
|
||||
amcfgV1beta1 := &monitoringv1beta1.AlertmanagerConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "amcfg-v1beta1",
|
||||
},
|
||||
Spec: monitoringv1beta1.AlertmanagerConfigSpec{
|
||||
Route: &monitoringv1beta1.Route{
|
||||
Receiver: "webhook",
|
||||
Matchers: []monitoringv1beta1.Matcher{{
|
||||
Name: "job",
|
||||
Value: "webapp.+",
|
||||
MatchType: "=~",
|
||||
}},
|
||||
},
|
||||
Receivers: []monitoringv1beta1.Receiver{{
|
||||
Name: "webhook",
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := framework.MonClientV1beta1.AlertmanagerConfigs(alertmanager.Namespace).Create(context.Background(), amcfgV1beta1, metav1.CreateOptions{}); err != nil {
|
||||
t.Fatalf("failed to create v1beta1 AlertmanagerConfig object: %v", err)
|
||||
}
|
||||
|
||||
if _, err := framework.MonClientV1alpha1.AlertmanagerConfigs(alertmanager.Namespace).Get(context.Background(), amcfgV1beta1.Name, metav1.GetOptions{}); err != nil {
|
||||
t.Fatalf("failed to get v1alpha1 AlertmanagerConfig object: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testAlertmanagerConfigCRD(t *testing.T) {
|
||||
// Don't run Alertmanager tests in parallel. See
|
||||
// https://github.com/prometheus/alertmanager/issues/1835 for details.
|
||||
|
|
|
@ -163,6 +163,7 @@ func testAllNSAlertmanager(t *testing.T) {
|
|||
"AMReloadConfig": testAMReloadConfig,
|
||||
"AMZeroDowntimeRollingDeployment": testAMZeroDowntimeRollingDeployment,
|
||||
"AMAlertmanagerConfigCRD": testAlertmanagerConfigCRD,
|
||||
"AMAlertmanagerConfigVersions": testAlertmanagerConfigVersions,
|
||||
"AMUserDefinedAMConfigFromSecret": testUserDefinedAlertmanagerConfigFromSecret,
|
||||
"AMUserDefinedAMConfigFromCustomResource": testUserDefinedAlertmanagerConfigFromCustomResource,
|
||||
"AMPreserveUserAddedMetadata": testAMPreserveUserAddedMetadata,
|
||||
|
|
|
@ -104,7 +104,7 @@ func WaitForCRDReady(listFunc func(opts metav1.ListOptions) (runtime.Object, err
|
|||
func (f *Framework) CreateCRDAndWaitUntilReady(ctx context.Context, crdName string, listFunc func(opts metav1.ListOptions) (runtime.Object, error)) error {
|
||||
crdName = strings.ToLower(crdName)
|
||||
group := monitoring.GroupName
|
||||
assetPath := "../../example/prometheus-operator-crd/" + group + "_" + crdName + ".yaml"
|
||||
assetPath := "../../example/prometheus-operator-crd-full/" + group + "_" + crdName + ".yaml"
|
||||
|
||||
crd, err := f.MakeCRD(assetPath)
|
||||
if err != nil {
|
||||
|
|
|
@ -16,6 +16,7 @@ package framework
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -24,12 +25,15 @@ import (
|
|||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
@ -41,6 +45,7 @@ import (
|
|||
monitoringv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
|
||||
v1monitoringclient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1"
|
||||
v1alpha1monitoringclient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1alpha1"
|
||||
v1beta1monitoringclient "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1beta1"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -56,6 +61,7 @@ type Framework struct {
|
|||
KubeClient kubernetes.Interface
|
||||
MonClientV1 v1monitoringclient.MonitoringV1Interface
|
||||
MonClientV1alpha1 v1alpha1monitoringclient.MonitoringV1alpha1Interface
|
||||
MonClientV1beta1 v1beta1monitoringclient.MonitoringV1beta1Interface
|
||||
APIServerClient apiclient.Interface
|
||||
HTTPClient *http.Client
|
||||
MasterHost string
|
||||
|
@ -90,17 +96,23 @@ func New(kubeconfig, opImage string) (*Framework, error) {
|
|||
return nil, errors.Wrap(err, "creating v1 monitoring client failed")
|
||||
}
|
||||
|
||||
mClientV1alpha1, err := v1alpha1monitoringclient.NewForConfig(config)
|
||||
mClientv1alpha1, err := v1alpha1monitoringclient.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating v1alpha1 monitoring client failed")
|
||||
}
|
||||
|
||||
mClientv1beta1, err := v1beta1monitoringclient.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating v1beta1 monitoring client failed")
|
||||
}
|
||||
|
||||
f := &Framework{
|
||||
RestConfig: config,
|
||||
MasterHost: config.Host,
|
||||
KubeClient: cli,
|
||||
MonClientV1: mClientV1,
|
||||
MonClientV1alpha1: mClientV1alpha1,
|
||||
MonClientV1alpha1: mClientv1alpha1,
|
||||
MonClientV1beta1: mClientv1beta1,
|
||||
APIServerClient: apiCli,
|
||||
HTTPClient: httpc,
|
||||
DefaultTimeout: time.Minute,
|
||||
|
@ -279,7 +291,14 @@ func (f *Framework) CreatePrometheusOperator(ctx context.Context, ns, opImage st
|
|||
return f.MonClientV1alpha1.AlertmanagerConfigs(v1.NamespaceAll).List(ctx, opts)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "initialize AlertmanagerConfig CRD")
|
||||
return nil, errors.Wrap(err, "initialize AlertmanagerConfig v1alpha1 CRD")
|
||||
}
|
||||
|
||||
err = WaitForCRDReady(func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
return f.MonClientV1beta1.AlertmanagerConfigs(v1.NamespaceAll).List(ctx, opts)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "wait for AlertmanagerConfig v1beta1 CRD")
|
||||
}
|
||||
|
||||
deploy, err := MakeDeployment("../../example/rbac/prometheus-operator/prometheus-operator-deployment.yaml")
|
||||
|
@ -387,7 +406,7 @@ func (f *Framework) CreatePrometheusOperator(ctx context.Context, ns, opImage st
|
|||
}
|
||||
|
||||
if createResourceAdmissionHooks {
|
||||
b, err := f.CreateAdmissionWebhookServer(ctx, ns, webhookServerImage)
|
||||
webhookService, b, err := f.CreateAdmissionWebhookServer(ctx, ns, webhookServerImage)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create webhook server")
|
||||
}
|
||||
|
@ -409,6 +428,12 @@ func (f *Framework) CreatePrometheusOperator(ctx context.Context, ns, opImage st
|
|||
return nil, errors.Wrap(err, "failed to create validating webhook for AlertManagerConfigs")
|
||||
}
|
||||
finalizers = append(finalizers, finalizer)
|
||||
|
||||
finalizer, err = f.configureAlertmanagerConfigConversion(ctx, webhookService, b)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to configure conversion webhook for AlertManagerConfigs")
|
||||
}
|
||||
finalizers = append(finalizers, finalizer)
|
||||
}
|
||||
|
||||
return finalizers, nil
|
||||
|
@ -448,14 +473,80 @@ func (f *Framework) SetupPrometheusRBACGlobal(ctx context.Context, t *testing.T,
|
|||
}
|
||||
}
|
||||
|
||||
func (f *Framework) configureAlertmanagerConfigConversion(ctx context.Context, svc *v1.Service, cert []byte) (FinalizerFn, error) {
|
||||
patch, err := f.MakeCRD("../../example/alertmanager-crd-conversion/patch.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
crd, err := f.GetCRD(ctx, patch.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
originalBytes, err := json.Marshal(crd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
patch.Spec.Conversion.Webhook.ClientConfig.Service.Name = svc.Name
|
||||
patch.Spec.Conversion.Webhook.ClientConfig.Service.Namespace = svc.Namespace
|
||||
patch.Spec.Conversion.Webhook.ClientConfig.Service.Port = &svc.Spec.Ports[0].Port
|
||||
patch.Spec.Conversion.Webhook.ClientConfig.CABundle = cert
|
||||
|
||||
crd.Spec.Conversion = patch.Spec.Conversion
|
||||
|
||||
patchBytes, err := json.Marshal(crd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
jsonResult, err := strategicpatch.StrategicMergePatch(originalBytes, patchBytes, apiextensionsv1.CustomResourceDefinition{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate merge patch: %w", err)
|
||||
}
|
||||
|
||||
crd, err = f.APIServerClient.ApiextensionsV1().CustomResourceDefinitions().Patch(
|
||||
ctx,
|
||||
crd.Name,
|
||||
types.StrategicMergePatchType,
|
||||
jsonResult,
|
||||
metav1.PatchOptions{},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to patch CustomResourceDefinition object: %w", err)
|
||||
}
|
||||
|
||||
if crd.Spec.Conversion.Strategy != apiextensionsv1.WebhookConverter {
|
||||
return nil, fmt.Errorf("expected conversion strategy to be %s, got %s", apiextensionsv1.WebhookConverter, crd.Spec.Conversion.Strategy)
|
||||
}
|
||||
|
||||
finalizerFn := func() error {
|
||||
crd, err := f.GetCRD(ctx, patch.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
crd.Spec.Conversion = nil
|
||||
_, err = f.APIServerClient.ApiextensionsV1().CustomResourceDefinitions().Update(ctx, crd, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to reset conversion configuration of AlertmanagerConfig CRD: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return finalizerFn, nil
|
||||
}
|
||||
|
||||
// CreateAdmissionWebhookServer deploys an HTTPS server
|
||||
// Acts as a validating and mutating webhook server for PrometheusRule and AlertManagerConfig
|
||||
// Returns the CA, which can be used to access the server over TLS
|
||||
// Returns the service and the CA which can be used to access the server over TLS
|
||||
func (f *Framework) CreateAdmissionWebhookServer(
|
||||
ctx context.Context,
|
||||
namespace string,
|
||||
image string,
|
||||
) ([]byte, error) {
|
||||
) (*v1.Service, []byte, error) {
|
||||
|
||||
certBytes, keyBytes, err := certutil.GenerateSelfSignedCertKey(
|
||||
fmt.Sprintf("%s.%s.svc", admissionWebhookServiceName, namespace),
|
||||
|
@ -463,18 +554,21 @@ func (f *Framework) CreateAdmissionWebhookServer(
|
|||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to generate certificate and key")
|
||||
return nil, nil, errors.Wrap(err, "failed to generate certificate and key")
|
||||
}
|
||||
|
||||
if err := f.CreateSecretWithCert(ctx, certBytes, keyBytes, namespace, standaloneAdmissionHookSecretName); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create admission webhook secret")
|
||||
return nil, nil, errors.Wrap(err, "failed to create admission webhook secret")
|
||||
}
|
||||
|
||||
deploy, err := MakeDeployment("../../example/admission-webhook/deployment.yaml")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Only 1 replica needed for the tests.
|
||||
deploy.Spec.Replicas = func(i int32) *int32 { return &i }(1)
|
||||
|
||||
deploy.Spec.Template.Spec.Containers[0].Args = append(deploy.Spec.Template.Spec.Containers[0].Args, "--log-level=debug")
|
||||
|
||||
if image != "" {
|
||||
|
@ -482,7 +576,7 @@ func (f *Framework) CreateAdmissionWebhookServer(
|
|||
deploy.Spec.Template.Spec.Containers[0].Image = image
|
||||
repoAndTag := strings.Split(image, ":")
|
||||
if len(repoAndTag) != 2 {
|
||||
return nil, errors.Errorf(
|
||||
return nil, nil, errors.Errorf(
|
||||
"expected image '%v' split by colon to result in two substrings but got '%v'",
|
||||
image,
|
||||
repoAndTag,
|
||||
|
@ -501,32 +595,31 @@ func (f *Framework) CreateAdmissionWebhookServer(
|
|||
|
||||
_, err = f.createServiceAccount(ctx, namespace, "../../example/admission-webhook/service-account.yaml")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = f.CreateDeployment(ctx, namespace, deploy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
opts := metav1.ListOptions{LabelSelector: fields.SelectorFromSet(fields.Set(deploy.Spec.Template.ObjectMeta.Labels)).String()}
|
||||
err = f.WaitForPodsReady(ctx, namespace, f.DefaultTimeout, 2, opts)
|
||||
err = f.WaitForPodsReady(ctx, namespace, f.DefaultTimeout, int(*deploy.Spec.Replicas), opts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to wait for admission webhook server to become ready")
|
||||
return nil, nil, errors.Wrap(err, "failed to wait for admission webhook server to become ready")
|
||||
}
|
||||
|
||||
service, err := MakeService("../../example/admission-webhook/service.yaml")
|
||||
if err != nil {
|
||||
return certBytes, errors.Wrap(err, "cannot parse service file")
|
||||
return nil, nil, errors.Wrap(err, "cannot parse service file")
|
||||
}
|
||||
|
||||
service.Namespace = namespace
|
||||
service.Spec.ClusterIP = ""
|
||||
service.Spec.Ports = []v1.ServicePort{{Name: "https", Port: 443, TargetPort: intstr.FromInt(8443)}}
|
||||
|
||||
if _, err := f.CreateServiceAndWaitUntilReady(ctx, namespace, service); err != nil {
|
||||
return certBytes, errors.Wrap(err, "failed to create admission webhook server service")
|
||||
return nil, nil, errors.Wrap(err, "failed to create admission webhook server service")
|
||||
}
|
||||
|
||||
return certBytes, nil
|
||||
return service, certBytes, nil
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ webhooks:
|
|||
- monitoring.coreos.com
|
||||
apiVersions:
|
||||
- v1alpha1
|
||||
- v1beta1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
|
@ -23,4 +24,4 @@ webhooks:
|
|||
- alertmanagerconfigs
|
||||
sideEffects: None
|
||||
admissionReviewVersions:
|
||||
- v1
|
||||
- v1
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue