podmonitor

Change-Id: Ie79dc54cb137c9d054f93dfc53b46f75a1470ea5
This commit is contained in:
olesandr kozachenko 2020-03-25 19:26:56 +02:00
parent cc5d82883c
commit f59f1e4d0c
18 changed files with 1186 additions and 0 deletions

View File

@ -0,0 +1,20 @@
// Package v1 contains API Schema definitions for the infrastructure v1 API group
// +kubebuilder:object:generate=true
// +groupName=monitoring.coreos.com
package v1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "monitoring.coreos.com", Version: "v1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)

View File

@ -0,0 +1,133 @@
package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
const (
Version = "v1"
PodMonitorsKind = "PodMonitor"
PodMonitorName = "podmonitors"
PodMonitorKindKey = "podmonitor"
)
// PodMonitor defines monitoring for a set of pods.
// +genclient
// +k8s:openapi-gen=true
// +kubebuilder:object:root=true
type PodMonitor struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Specification of desired Pod selection for target discovery by Prometheus.
Spec PodMonitorSpec `json:"spec"`
}
// PodMonitorSpec contains specification parameters for a PodMonitor.
// +k8s:openapi-gen=true
type PodMonitorSpec struct {
// The label to use to retrieve the job name from.
JobLabel string `json:"jobLabel,omitempty"`
// PodTargetLabels transfers labels on the Kubernetes Pod onto the target.
PodTargetLabels []string `json:"podTargetLabels,omitempty"`
// A list of endpoints allowed as part of this PodMonitor.
PodMetricsEndpoints []PodMetricsEndpoint `json:"podMetricsEndpoints"`
// Selector to select Pod objects.
Selector metav1.LabelSelector `json:"selector"`
// Selector to select which namespaces the Endpoints objects are discovered from.
NamespaceSelector NamespaceSelector `json:"namespaceSelector,omitempty"`
// SampleLimit defines per-scrape limit on number of scraped samples that will be accepted.
SampleLimit uint64 `json:"sampleLimit,omitempty"`
}
// PodMonitorList is a list of PodMonitors.
// +k8s:openapi-gen=true
// +kubebuilder:object:root=true
type PodMonitorList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata
// More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata
metav1.ListMeta `json:"metadata,omitempty"`
// List of PodMonitors
Items []*PodMonitor `json:"items"`
}
// 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
// +k8s:openapi-gen=true
type RelabelConfig struct {
//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.
SourceLabels []string `json:"sourceLabels,omitempty"`
//Separator placed between concatenated source label values. default is ';'.
Separator string `json:"separator,omitempty"`
//Label to which the resulting value is written in a replace action.
//It is mandatory for replace actions. Regex capture groups are available.
TargetLabel string `json:"targetLabel,omitempty"`
//Regular expression against which the extracted value is matched. Default is '(.*)'
Regex string `json:"regex,omitempty"`
// Modulus to take of the hash of the source label values.
Modulus uint64 `json:"modulus,omitempty"`
//Replacement value against which a regex replace is performed if the
//regular expression matches. Regex capture groups are available. Default is '$1'
Replacement string `json:"replacement,omitempty"`
// Action to perform based on regex matching. Default is 'replace'
Action string `json:"action,omitempty"`
}
// PodMetricsEndpoint defines a scrapeable endpoint of a Kubernetes Pod serving Prometheus metrics.
// +k8s:openapi-gen=true
type PodMetricsEndpoint struct {
// Name of the pod port this endpoint refers to. Mutually exclusive with targetPort.
Port string `json:"port,omitempty"`
// Deprecated: Use 'port' instead.
TargetPort *intstr.IntOrString `json:"targetPort,omitempty"`
// HTTP path to scrape for metrics.
Path string `json:"path,omitempty"`
// HTTP scheme to use for scraping.
Scheme string `json:"scheme,omitempty"`
// Optional HTTP URL parameters
Params map[string][]string `json:"params,omitempty"`
// Interval at which metrics should be scraped
Interval string `json:"interval,omitempty"`
// Timeout after which the scrape is ended
ScrapeTimeout string `json:"scrapeTimeout,omitempty"`
// HonorLabels chooses the metric's labels on collisions with target labels.
HonorLabels bool `json:"honorLabels,omitempty"`
// HonorTimestamps controls whether Prometheus respects the timestamps present in scraped data.
HonorTimestamps *bool `json:"honorTimestamps,omitempty"`
// MetricRelabelConfigs to apply to samples before ingestion.
MetricRelabelConfigs []*RelabelConfig `json:"metricRelabelings,omitempty"`
// RelabelConfigs to apply to samples before ingestion.
// More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
RelabelConfigs []*RelabelConfig `json:"relabelings,omitempty"`
// ProxyURL eg http://proxyserver:2195 Directs scrapes to proxy through this endpoint.
ProxyURL *string `json:"proxyUrl,omitempty"`
}
// NamespaceSelector is a selector for selecting either all namespaces or a
// list of namespaces.
// +k8s:openapi-gen=true
type NamespaceSelector struct {
// Boolean describing whether all namespaces are selected in contrast to a
// list restricting them.
Any bool `json:"any,omitempty"`
// List of namespace names.
MatchNames []string `json:"matchNames,omitempty"`
// TODO(fabxc): this should embed metav1.LabelSelector eventually.
// Currently the selector is only used for namespaces which require more complex
// implementation to support label selections.
}
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=podmonitors,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=podmonitors/status,verbs=get;update;patch
func init() {
SchemeBuilder.Register(&PodMonitor{}, &PodMonitorList{})
}

View File

@ -0,0 +1,224 @@
// +build !ignore_autogenerated
/*
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 v1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NamespaceSelector) DeepCopyInto(out *NamespaceSelector) {
*out = *in
if in.MatchNames != nil {
in, out := &in.MatchNames, &out.MatchNames
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceSelector.
func (in *NamespaceSelector) DeepCopy() *NamespaceSelector {
if in == nil {
return nil
}
out := new(NamespaceSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodMetricsEndpoint) DeepCopyInto(out *PodMetricsEndpoint) {
*out = *in
if in.TargetPort != nil {
in, out := &in.TargetPort, &out.TargetPort
*out = new(intstr.IntOrString)
**out = **in
}
if in.Params != nil {
in, out := &in.Params, &out.Params
*out = make(map[string][]string, len(*in))
for key, val := range *in {
var outVal []string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make([]string, len(*in))
copy(*out, *in)
}
(*out)[key] = outVal
}
}
if in.HonorTimestamps != nil {
in, out := &in.HonorTimestamps, &out.HonorTimestamps
*out = new(bool)
**out = **in
}
if in.MetricRelabelConfigs != nil {
in, out := &in.MetricRelabelConfigs, &out.MetricRelabelConfigs
*out = make([]*RelabelConfig, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(RelabelConfig)
(*in).DeepCopyInto(*out)
}
}
}
if in.RelabelConfigs != nil {
in, out := &in.RelabelConfigs, &out.RelabelConfigs
*out = make([]*RelabelConfig, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(RelabelConfig)
(*in).DeepCopyInto(*out)
}
}
}
if in.ProxyURL != nil {
in, out := &in.ProxyURL, &out.ProxyURL
*out = new(string)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodMetricsEndpoint.
func (in *PodMetricsEndpoint) DeepCopy() *PodMetricsEndpoint {
if in == nil {
return nil
}
out := new(PodMetricsEndpoint)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodMonitor) DeepCopyInto(out *PodMonitor) {
*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 PodMonitor.
func (in *PodMonitor) DeepCopy() *PodMonitor {
if in == nil {
return nil
}
out := new(PodMonitor)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PodMonitor) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodMonitorList) DeepCopyInto(out *PodMonitorList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]*PodMonitor, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(PodMonitor)
(*in).DeepCopyInto(*out)
}
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodMonitorList.
func (in *PodMonitorList) DeepCopy() *PodMonitorList {
if in == nil {
return nil
}
out := new(PodMonitorList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PodMonitorList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodMonitorSpec) DeepCopyInto(out *PodMonitorSpec) {
*out = *in
if in.PodTargetLabels != nil {
in, out := &in.PodTargetLabels, &out.PodTargetLabels
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.PodMetricsEndpoints != nil {
in, out := &in.PodMetricsEndpoints, &out.PodMetricsEndpoints
*out = make([]PodMetricsEndpoint, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.Selector.DeepCopyInto(&out.Selector)
in.NamespaceSelector.DeepCopyInto(&out.NamespaceSelector)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodMonitorSpec.
func (in *PodMonitorSpec) DeepCopy() *PodMonitorSpec {
if in == nil {
return nil
}
out := new(PodMonitorSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RelabelConfig) DeepCopyInto(out *RelabelConfig) {
*out = *in
if in.SourceLabels != nil {
in, out := &in.SourceLabels, &out.SourceLabels
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RelabelConfig.
func (in *RelabelConfig) DeepCopy() *RelabelConfig {
if in == nil {
return nil
}
out := new(RelabelConfig)
in.DeepCopyInto(out)
return out
}

0
api/v1alpha1/groupversion_info.go Normal file → Executable file
View File

0
api/v1alpha1/mcrouter_types.go Normal file → Executable file
View File

0
api/v1alpha1/memcached_types.go Normal file → Executable file
View File

0
api/v1alpha1/zz_generated.deepcopy.go Normal file → Executable file
View File

View File

@ -0,0 +1,68 @@
package builders
import (
"k8s.io/apimachinery/pkg/util/intstr"
monitoringv1 "opendev.org/vexxhost/openstack-operator/api/monitoring/v1"
)
// PodMetricsEndpointBuilder provides an interface to build podmonitors
type PodMetricsEndpointBuilder struct {
obj *monitoringv1.PodMetricsEndpoint
}
// PodMonitor returns a new podmonitor builder
func PodMetricsEndpoint() *PodMetricsEndpointBuilder {
podMetricsEndpoint := &monitoringv1.PodMetricsEndpoint{}
return &PodMetricsEndpointBuilder{
obj: podMetricsEndpoint,
}
}
func (pme *PodMetricsEndpointBuilder) Port(port string) *PodMetricsEndpointBuilder {
pme.obj.Port = port
return pme
}
func (pme *PodMetricsEndpointBuilder) TargetPort(targetPort intstr.IntOrString) *PodMetricsEndpointBuilder {
pme.obj.TargetPort = &targetPort
return pme
}
func (pme *PodMetricsEndpointBuilder) Path(path string) *PodMetricsEndpointBuilder {
pme.obj.Path = path
return pme
}
func (pme *PodMetricsEndpointBuilder) Scheme(scheme string) *PodMetricsEndpointBuilder {
pme.obj.Scheme = scheme
return pme
}
func (pme *PodMetricsEndpointBuilder) Params(params map[string][]string) *PodMetricsEndpointBuilder {
pme.obj.Params = params
return pme
}
func (pme *PodMetricsEndpointBuilder) Interval(interval string) *PodMetricsEndpointBuilder {
pme.obj.Interval = interval
return pme
}
func (pme *PodMetricsEndpointBuilder) ScrapeTimeout(scrapeTimeout string) *PodMetricsEndpointBuilder {
pme.obj.ScrapeTimeout = scrapeTimeout
return pme
}
func (pme *PodMetricsEndpointBuilder) HonorLabels(honorLabels bool) *PodMetricsEndpointBuilder {
pme.obj.HonorLabels = honorLabels
return pme
}
func (pme *PodMetricsEndpointBuilder) HonorTimestamps(honorTimestamps bool) *PodMetricsEndpointBuilder {
pme.obj.HonorTimestamps = &honorTimestamps
return pme
}
func (pme *PodMetricsEndpointBuilder) ProxyURL(proxyURL string) *PodMetricsEndpointBuilder {
pme.obj.ProxyURL = &proxyURL
return pme
}
// Build returns the object after making certain assertions
func (pme *PodMetricsEndpointBuilder) Build() (monitoringv1.PodMetricsEndpoint, error) {
return *pme.obj, nil
}

92
builders/pod_monitor.go Executable file
View File

@ -0,0 +1,92 @@
package builders
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
monitoringv1 "opendev.org/vexxhost/openstack-operator/api/monitoring/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
// PodMonitorBuilder provides an interface to build podmonitors
type PodMonitorBuilder struct {
obj *monitoringv1.PodMonitor
podMetricsEndpoints []*PodMetricsEndpointBuilder
owner metav1.Object
scheme *runtime.Scheme
}
// PodMonitor returns a new podmonitor builder
func PodMonitor(existing *monitoringv1.PodMonitor, owner metav1.Object, scheme *runtime.Scheme) *PodMonitorBuilder {
return &PodMonitorBuilder{
obj: existing,
owner: owner,
scheme: scheme,
}
}
func (pm *PodMonitorBuilder) Selector(matchLabels map[string]string) *PodMonitorBuilder {
pm.obj.Spec.Selector = metav1.LabelSelector{
MatchLabels: matchLabels,
}
return pm
}
func (pm *PodMonitorBuilder) PodTargetLabels(podTargetLabels []string) *PodMonitorBuilder {
pm.obj.Spec.PodTargetLabels = podTargetLabels
return pm
}
func (pm *PodMonitorBuilder) JobLabel(jobLabel string) *PodMonitorBuilder {
pm.obj.Spec.JobLabel = jobLabel
return pm
}
func (pm *PodMonitorBuilder) NamespaceSelector(any bool, matchNames []string) *PodMonitorBuilder {
pm.obj.Spec.NamespaceSelector = monitoringv1.NamespaceSelector{
Any: any,
MatchNames: matchNames,
}
return pm
}
func (pm *PodMonitorBuilder) SampleLimit(sampleLimit uint64) *PodMonitorBuilder {
pm.obj.Spec.SampleLimit = sampleLimit
return pm
}
func (pm *PodMonitorBuilder) PodMetricsEndpoints(pme ...*PodMetricsEndpointBuilder) *PodMonitorBuilder {
pm.podMetricsEndpoints = pme
return pm
}
// Build returns the object after making certain assertions
func (pm *PodMonitorBuilder) Build() error {
pm.obj.Spec.PodMetricsEndpoints = []monitoringv1.PodMetricsEndpoint{}
for _, pmeBuilder := range pm.podMetricsEndpoints {
podMetricsEndpoint, err := pmeBuilder.Build()
if err != nil {
return err
}
pm.obj.Spec.PodMetricsEndpoints = append(pm.obj.Spec.PodMetricsEndpoints, podMetricsEndpoint)
}
if !pm.isOwnedByOthers() {
return controllerutil.SetControllerReference(pm.owner, pm.obj, pm.scheme)
}
return nil
}
// isOwnedByOthers checks if this podMonitor has been possessed by an another object already.
func (pm *PodMonitorBuilder) isOwnedByOthers() bool {
ownerName := pm.owner.GetName()
existingRefs := pm.obj.GetOwnerReferences()
for _, r := range existingRefs {
if r.Name == ownerName {
return false
} else if r.Controller != nil && *r.Controller {
return true
}
}
return false
}

View File

@ -0,0 +1,265 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.2.5
creationTimestamp: null
name: podmonitors.monitoring.coreos.com
spec:
group: monitoring.coreos.com
names:
kind: PodMonitor
listKind: PodMonitorList
plural: podmonitors
singular: podmonitor
scope: Namespaced
validation:
openAPIV3Schema:
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:
jobLabel:
description: The label to use to retrieve the job name from.
type: string
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.
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:
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
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:
description: Action to perform based on regex matching.
Default is 'replace'
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:
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
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 ingestion.
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:
description: Action to perform based on regex matching.
Default is 'replace'
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:
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
type: string
targetPort:
anyOf:
- type: integer
- type: string
description: 'Deprecated: Use ''port'' instead.'
x-kubernetes-int-or-string: true
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
required:
- podMetricsEndpoints
- selector
type: object
required:
- spec
type: object
version: v1
versions:
- name: v1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -83,3 +83,23 @@ rules:
- get
- patch
- update
- apiGroups:
- monitoring.coreos.com
resources:
- podmonitors
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- monitoring.coreos.com
resources:
- podmonitors/status
verbs:
- get
- patch
- update

View File

@ -0,0 +1,265 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.2.5
creationTimestamp: null
name: podmonitors.monitoring.coreos.com
spec:
group: monitoring.coreos.com
names:
kind: PodMonitor
listKind: PodMonitorList
plural: podmonitors
singular: podmonitor
scope: Namespaced
validation:
openAPIV3Schema:
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:
jobLabel:
description: The label to use to retrieve the job name from.
type: string
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.
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:
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
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:
description: Action to perform based on regex matching.
Default is 'replace'
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:
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
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 ingestion.
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:
description: Action to perform based on regex matching.
Default is 'replace'
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:
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
type: string
targetPort:
anyOf:
- type: integer
- type: string
description: 'Deprecated: Use ''port'' instead.'
x-kubernetes-int-or-string: true
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
required:
- podMetricsEndpoints
- selector
type: object
required:
- spec
type: object
version: v1
versions:
- name: v1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -4,6 +4,7 @@
resources:
- bases/infrastructure.vexxhost.cloud_mcrouters.yaml
- bases/infrastructure.vexxhost.cloud_memcacheds.yaml
- bases/monitoring.coreos.com_podmonitors.yaml
# +kubebuilder:scaffold:crdkustomizeresource
patchesStrategicMerge:

View File

@ -83,3 +83,23 @@ rules:
- get
- patch
- update
- apiGroups:
- monitoring.coreos.com
resources:
- podmonitors
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- monitoring.coreos.com
resources:
- podmonitors/status
verbs:
- get
- patch
- update

View File

@ -13,6 +13,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
monitoringv1 "opendev.org/vexxhost/openstack-operator/api/monitoring/v1"
infrastructurev1alpha1 "opendev.org/vexxhost/openstack-operator/api/v1alpha1"
"opendev.org/vexxhost/openstack-operator/builders"
"opendev.org/vexxhost/openstack-operator/utils"
@ -28,6 +29,7 @@ type McrouterReconciler struct {
// +kubebuilder:rbac:groups=infrastructure.vexxhost.cloud,resources=mcrouters,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=infrastructure.vexxhost.cloud,resources=mcrouters/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=podmonitors,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=configmaps;services,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
@ -118,6 +120,39 @@ func (r *McrouterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
}
log.WithValues("resource", "Deployment").WithValues("op", op).Info("Reconciled")
// PodMonitor
podMonitor := &monitoringv1.PodMonitor{
TypeMeta: metav1.TypeMeta{
APIVersion: "monitoring.coreos.com/v1",
Kind: "PodMonitor",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: req.Namespace,
Name: fmt.Sprintf("mcrouter-podmonitor"),
Labels: map[string]string{
"app.kubernetes.io/name": "mcrouter",
},
},
}
op, err = utils.CreateOrUpdate(ctx, r, podMonitor, func() error {
return builders.PodMonitor(podMonitor, &mcrouter, r.Scheme).
Selector(map[string]string{
"app.kubernetes.io/name": "mcrouter",
}).
PodMetricsEndpoints(
builders.PodMetricsEndpoint().
Port("metrics").
Path("/metrics").
Interval("15s"),
).Build()
})
if err != nil {
return ctrl.Result{}, err
}
log.WithValues("resource", "podmonitor").WithValues("op", op).Info("Reconciled")
// Service
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
@ -146,5 +181,6 @@ func (r *McrouterReconciler) SetupWithManager(mgr ctrl.Manager) error {
Owns(&corev1.ConfigMap{}).
Owns(&appsv1.Deployment{}).
Owns(&corev1.Service{}).
Owns(&monitoringv1.PodMonitor{}).
Complete(r)
}

View File

@ -32,6 +32,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
infrastructurev1alpha1 "opendev.org/vexxhost/openstack-operator/api/v1alpha1"
monitoringv1 "opendev.org/vexxhost/openstack-operator/api/monitoring/v1"
"opendev.org/vexxhost/openstack-operator/builders"
"opendev.org/vexxhost/openstack-operator/utils"
)
@ -46,6 +48,7 @@ type MemcachedReconciler struct {
// +kubebuilder:rbac:groups=infrastructure.vexxhost.cloud,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=infrastructure.vexxhost.cloud,resources=memcacheds/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=podmonitors,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
@ -76,6 +79,7 @@ func (r *MemcachedReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
Labels: labels,
},
}
op, err := utils.CreateOrUpdate(ctx, r, deployment, func() error {
return builders.Deployment(deployment, &memcached, r.Scheme).
Labels(labels).
@ -113,6 +117,40 @@ func (r *MemcachedReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
}
log.WithValues("resource", "Deployment").WithValues("op", op).Info("Reconciled")
// PodMonitor
podMonitor := &monitoringv1.PodMonitor{
TypeMeta: metav1.TypeMeta{
APIVersion: "monitoring.coreos.com/v1",
Kind: "PodMonitor",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: req.Namespace,
Name: fmt.Sprintf("memcached-podmonitor"),
Labels: map[string]string{
"app.kubernetes.io/name": "memcached",
},
},
}
op, err = utils.CreateOrUpdate(ctx, r, podMonitor, func() error {
return builders.PodMonitor(podMonitor, &memcached, r.Scheme).
Selector(map[string]string{
"app.kubernetes.io/name": "memcached",
}).
PodMetricsEndpoints(
builders.PodMetricsEndpoint().
Port("metrics").
Path("/metrics").
Interval("15s"),
).Build()
})
if err != nil {
return ctrl.Result{}, err
}
log.WithValues("resource", "podmonitor").WithValues("op", op).Info("Reconciled")
// Pods
pods := &corev1.PodList{}
err = r.List(ctx, pods, client.InNamespace(req.Namespace), client.MatchingLabels(labels))
@ -175,5 +213,6 @@ func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
For(&infrastructurev1alpha1.Memcached{}).
Owns(&appsv1.Deployment{}).
Owns(&infrastructurev1alpha1.Mcrouter{}).
Owns(&monitoringv1.PodMonitor{}).
Complete(r)
}

2
main.go Normal file → Executable file
View File

@ -26,6 +26,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
monitoringv1 "opendev.org/vexxhost/openstack-operator/api/monitoring/v1"
infrastructurev1alpha1 "opendev.org/vexxhost/openstack-operator/api/v1alpha1"
"opendev.org/vexxhost/openstack-operator/controllers"
"opendev.org/vexxhost/openstack-operator/version"
@ -41,6 +42,7 @@ func init() {
_ = clientgoscheme.AddToScheme(scheme)
_ = infrastructurev1alpha1.AddToScheme(scheme)
_ = monitoringv1.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
}

View File

@ -13,6 +13,7 @@ import (
// CreateOrUpdate wraps the function provided by controller-runtime to include
// some additional logging and common functionality across all resources.
func CreateOrUpdate(ctx context.Context, c client.Client, obj runtime.Object, f controllerutil.MutateFn) (controllerutil.OperationResult, error) {
return controllerutil.CreateOrUpdate(ctx, c, obj, func() error {
original := obj.DeepCopyObject()