1
0
Fork 0
mirror of https://github.com/prometheus-operator/prometheus-operator.git synced 2025-04-21 03:38:43 +00:00

Feat: Add servicename field to the Prometheus server and agent CRDs ()

This commit is contained in:
M Viswanath Sai 2025-01-15 18:21:32 +05:30 committed by GitHub
parent 4d26aaecf6
commit 78bffbb698
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 527 additions and 25 deletions

View file

@ -3103,6 +3103,23 @@ It requires Prometheus &gt;= v2.39.0 or PrometheusAgent &gt;= v2.54.0.</p>
</tr>
<tr>
<td>
<code>serviceName</code><br/>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named <code>prometheus-operated</code> for Prometheus resources,
or <code>prometheus-agent-operated</code> for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See <a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id">https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id</a> for more details.</p>
</td>
</tr>
<tr>
<td>
<code>runtime</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.RuntimeConfig">
@ -8247,6 +8264,23 @@ It requires Prometheus &gt;= v2.39.0 or PrometheusAgent &gt;= v2.54.0.</p>
</tr>
<tr>
<td>
<code>serviceName</code><br/>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named <code>prometheus-operated</code> for Prometheus resources,
or <code>prometheus-agent-operated</code> for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See <a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id">https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id</a> for more details.</p>
</td>
</tr>
<tr>
<td>
<code>runtime</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.RuntimeConfig">
@ -13109,6 +13143,23 @@ It requires Prometheus &gt;= v2.39.0 or PrometheusAgent &gt;= v2.54.0.</p>
</tr>
<tr>
<td>
<code>serviceName</code><br/>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named <code>prometheus-operated</code> for Prometheus resources,
or <code>prometheus-agent-operated</code> for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See <a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id">https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id</a> for more details.</p>
</td>
</tr>
<tr>
<td>
<code>runtime</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.RuntimeConfig">
@ -19889,6 +19940,23 @@ It requires Prometheus &gt;= v2.39.0 or PrometheusAgent &gt;= v2.54.0.</p>
</tr>
<tr>
<td>
<code>serviceName</code><br/>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named <code>prometheus-operated</code> for Prometheus resources,
or <code>prometheus-agent-operated</code> for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See <a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id">https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id</a> for more details.</p>
</td>
</tr>
<tr>
<td>
<code>runtime</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.RuntimeConfig">
@ -27850,6 +27918,23 @@ It requires Prometheus &gt;= v2.39.0 or PrometheusAgent &gt;= v2.54.0.</p>
</tr>
<tr>
<td>
<code>serviceName</code><br/>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named <code>prometheus-operated</code> for Prometheus resources,
or <code>prometheus-agent-operated</code> for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See <a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id">https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id</a> for more details.</p>
</td>
</tr>
<tr>
<td>
<code>runtime</code><br/>
<em>
<a href="#monitoring.coreos.com/v1.RuntimeConfig">

20
bundle.yaml generated
View file

@ -28427,6 +28427,16 @@ spec:
type: object
type: object
x-kubernetes-map-type: atomic
serviceName:
description: |-
The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,
or `prometheus-agent-operated` for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.
minLength: 1
type: string
shards:
description: |-
Number of shards to distribute scraped targets onto.
@ -40920,6 +40930,16 @@ spec:
type: object
type: object
x-kubernetes-map-type: atomic
serviceName:
description: |-
The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,
or `prometheus-agent-operated` for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.
minLength: 1
type: string
sha:
description: 'Deprecated: use ''spec.image'' instead. The image''s
digest can be specified as part of the image name.'

View file

@ -7267,6 +7267,16 @@ spec:
type: object
type: object
x-kubernetes-map-type: atomic
serviceName:
description: |-
The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,
or `prometheus-agent-operated` for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.
minLength: 1
type: string
shards:
description: |-
Number of shards to distribute scraped targets onto.

View file

@ -8976,6 +8976,16 @@ spec:
type: object
type: object
x-kubernetes-map-type: atomic
serviceName:
description: |-
The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,
or `prometheus-agent-operated` for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.
minLength: 1
type: string
sha:
description: 'Deprecated: use ''spec.image'' instead. The image''s
digest can be specified as part of the image name.'

View file

@ -7268,6 +7268,16 @@ spec:
type: object
type: object
x-kubernetes-map-type: atomic
serviceName:
description: |-
The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,
or `prometheus-agent-operated` for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.
minLength: 1
type: string
shards:
description: |-
Number of shards to distribute scraped targets onto.

View file

@ -8977,6 +8977,16 @@ spec:
type: object
type: object
x-kubernetes-map-type: atomic
serviceName:
description: |-
The name of the service name used by the underlying StatefulSet(s) as the governing service.
If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
If empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,
or `prometheus-agent-operated` for PrometheusAgent resources.
When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.
minLength: 1
type: string
sha:
description: 'Deprecated: use ''spec.image'' instead. The image''s
digest can be specified as part of the image name.'

View file

@ -6151,6 +6151,11 @@
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"serviceName": {
"description": "The name of the service name used by the underlying StatefulSet(s) as the governing service.\nIf defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.\nIf empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,\nor `prometheus-agent-operated` for PrometheusAgent resources.\nWhen deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.\nSee https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.",
"minLength": 1,
"type": "string"
},
"shards": {
"description": "Number of shards to distribute scraped targets onto.\n\n`spec.replicas` multiplied by `spec.shards` is the total number of Pods\nbeing created.\n\nWhen not defined, the operator assumes only one shard.\n\nNote that scaling down shards will not reshard data onto the remaining\ninstances, it must be manually moved. Increasing shards will not reshard\ndata either but it will continue to be available from the same\ninstances. To query globally, use Thanos sidecar and Thanos querier or\nremote write data to a central location.\nAlerting and recording rules\n\nBy default, the sharding is performed on:\n* The `__address__` target's metadata label for PodMonitor,\nServiceMonitor and ScrapeConfig resources.\n* The `__param_target__` label for Probe resources.\n\nUsers can define their own sharding implementation by setting the\n`__tmp_hash` label during the target discovery with relabeling\nconfiguration (either in the monitoring resources or via scrape class).",
"format": "int32",

View file

@ -7659,6 +7659,11 @@
"type": "object",
"x-kubernetes-map-type": "atomic"
},
"serviceName": {
"description": "The name of the service name used by the underlying StatefulSet(s) as the governing service.\nIf defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.\nIf empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,\nor `prometheus-agent-operated` for PrometheusAgent resources.\nWhen deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.\nSee https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.",
"minLength": 1,
"type": "string"
},
"sha": {
"description": "Deprecated: use 'spec.image' instead. The image's digest can be specified as part of the image name.",
"type": "string"

View file

@ -857,6 +857,16 @@ type CommonPrometheusFields struct {
// +optional
TSDB *TSDBSpec `json:"tsdb,omitempty"`
// The name of the service name used by the underlying StatefulSet(s) as the governing service.
// If defined, the Service must be created before the Prometheus/PrometheusAgent resource in the same namespace and it must define a selector that matches the pod labels.
// If empty, the operator will create and manage a headless service named `prometheus-operated` for Prometheus resources,
// or `prometheus-agent-operated` for PrometheusAgent resources.
// When deploying multiple Prometheus/PrometheusAgent resources in the same namespace, it is recommended to specify a different value for each.
// See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-network-id for more details.
// +optional
// +kubebuilder:validation:MinLength=1
ServiceName *string `json:"serviceName,omitempty"`
// RuntimeConfig configures the values for the Prometheus process behavior
// +optional
Runtime *RuntimeConfig `json:"runtime,omitempty"`

View file

@ -1035,6 +1035,11 @@ func (in *CommonPrometheusFields) DeepCopyInto(out *CommonPrometheusFields) {
*out = new(TSDBSpec)
(*in).DeepCopyInto(*out)
}
if in.ServiceName != nil {
in, out := &in.ServiceName, &out.ServiceName
*out = new(string)
**out = **in
}
if in.Runtime != nil {
in, out := &in.Runtime, &out.Runtime
*out = new(RuntimeConfig)

View file

@ -115,6 +115,7 @@ type CommonPrometheusFieldsApplyConfiguration struct {
ScrapeClasses []ScrapeClassApplyConfiguration `json:"scrapeClasses,omitempty"`
ServiceDiscoveryRole *monitoringv1.ServiceDiscoveryRole `json:"serviceDiscoveryRole,omitempty"`
TSDB *TSDBSpecApplyConfiguration `json:"tsdb,omitempty"`
ServiceName *string `json:"serviceName,omitempty"`
Runtime *RuntimeConfigApplyConfiguration `json:"runtime,omitempty"`
}
@ -902,6 +903,14 @@ func (b *CommonPrometheusFieldsApplyConfiguration) WithTSDB(value *TSDBSpecApply
return b
}
// WithServiceName sets the ServiceName field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ServiceName field is set to the value of the last call.
func (b *CommonPrometheusFieldsApplyConfiguration) WithServiceName(value string) *CommonPrometheusFieldsApplyConfiguration {
b.ServiceName = &value
return b
}
// WithRuntime sets the Runtime field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Runtime field is set to the value of the last call.

View file

@ -835,6 +835,14 @@ func (b *PrometheusSpecApplyConfiguration) WithTSDB(value *TSDBSpecApplyConfigur
return b
}
// WithServiceName sets the ServiceName field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ServiceName field is set to the value of the last call.
func (b *PrometheusSpecApplyConfiguration) WithServiceName(value string) *PrometheusSpecApplyConfiguration {
b.ServiceName = &value
return b
}
// WithRuntime sets the Runtime field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Runtime field is set to the value of the last call.

View file

@ -824,6 +824,14 @@ func (b *PrometheusAgentSpecApplyConfiguration) WithTSDB(value *v1.TSDBSpecApply
return b
}
// WithServiceName sets the ServiceName field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the ServiceName field is set to the value of the last call.
func (b *PrometheusAgentSpecApplyConfiguration) WithServiceName(value string) *PrometheusAgentSpecApplyConfiguration {
b.ServiceName = &value
return b
}
// WithRuntime sets the Runtime field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Runtime field is set to the value of the last call.

View file

@ -692,15 +692,24 @@ func (c *Operator) syncDaemonSet(ctx context.Context, key string, p *monitoringv
func (c *Operator) syncStatefulSet(ctx context.Context, key string, p *monitoringv1alpha1.PrometheusAgent, cg *prompkg.ConfigGenerator, tlsAssets *operator.ShardedSecret) error {
logger := c.logger.With("key", key)
// Reconcile the governing service.
svc := prompkg.BuildStatefulSetService(
governingServiceName,
map[string]string{"app.kubernetes.io/name": "prometheus-agent"},
p,
c.config,
)
if _, err := k8sutil.CreateOrUpdateService(ctx, c.kclient.CoreV1().Services(p.Namespace), svc); err != nil {
return fmt.Errorf("synchronizing governing service failed: %w", err)
if p.Spec.ServiceName != nil {
svcClient := c.kclient.CoreV1().Services(p.Namespace)
selectorLabels := makeSelectorLabels(p.Name)
if err := prompkg.EnsureCustomGoverningService(ctx, p.Namespace, *p.Spec.ServiceName, svcClient, selectorLabels); err != nil {
return err
}
} else {
svc := prompkg.BuildStatefulSetService(
governingServiceName,
map[string]string{"app.kubernetes.io/name": "prometheus-agent"},
p,
c.config,
)
if _, err := k8sutil.CreateOrUpdateService(ctx, c.kclient.CoreV1().Services(p.Namespace), svc); err != nil {
return fmt.Errorf("synchronizing default governing service failed: %w", err)
}
}
ssetClient := c.kclient.AppsV1().StatefulSets(p.Namespace)

View file

@ -16,6 +16,7 @@ package prometheus
import (
"bytes"
"context"
"fmt"
"net/url"
"path"
@ -23,7 +24,9 @@ import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/intstr"
clientv1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@ -474,3 +477,32 @@ func BuildStatefulSetService(name string, selector map[string]string, p monitori
return svc
}
// This function is responsible for the following:
//
// Verify that the service exists in the Prometheus/PrometheusAgent resource's namespace
// If it does not exist, fail the reconciliation.
//
// If the ServiceName is specified and a service with the same name exists in the same namespace as the
// Prometheus/PrometheusAgent resource, ensure that the custom governing service's selector matches the
// Prometheus/PrometheusAgent statefulsets.
// If it is not selected, fail the reconciliation
// Warning: the function will panic if the resource's ServiceName is nil..
func EnsureCustomGoverningService(ctx context.Context, namespace string, serviceName string, svcClient clientv1.ServiceInterface, selectorLabels map[string]string) error {
// Check if the custom governing service is defined in the same namespace and selects the Prometheus pod.
svc, err := svcClient.Get(ctx, serviceName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to get custom governing service %s/%s: %w", namespace, serviceName, err)
}
svcSelector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: svc.Spec.Selector})
if err != nil {
return fmt.Errorf("failed to parse the selector labels for custom governing service %s/%s: %w", namespace, serviceName, err)
}
if !svcSelector.Matches(labels.Set(selectorLabels)) {
return fmt.Errorf("custom governing service %s/%s with selector %q does not select Prometheus/PrometheusAgent pods with labels %q",
namespace, serviceName, svcSelector.String(), labels.Set(selectorLabels).String())
}
return nil
}

View file

@ -15,11 +15,14 @@
package prometheus
import (
"context"
"strings"
"testing"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/utils/ptr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@ -282,3 +285,153 @@ func TestBuildCommonPrometheusArgsWithOTLPReceiver(t *testing.T) {
})
}
}
func TestEnsureCustomGoverningService(t *testing.T) {
name := "test-prometheus"
serviceName := "test-svc"
ns := "test-ns"
testcases := []struct {
name string
service v1.Service
selectorLabels map[string]string
expectedErr bool
}{
{
name: "custom service selects prometheus",
service: v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: serviceName,
Namespace: ns,
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
},
},
selectorLabels: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
expectedErr: false,
},
{
name: "custom service does not select prometheus",
service: v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-svc",
Namespace: ns,
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"prometheus": "different-name",
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": "different-name",
"app.kubernetes.io/managed-by": "prometheus-operator",
},
},
},
selectorLabels: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
expectedErr: true,
},
{
name: "custom service selects prometheus but in different ns",
service: v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-svc",
Namespace: "wrong-ns",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
},
},
selectorLabels: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
expectedErr: true,
},
{
name: "custom service selects prometheus but in different ns",
service: v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-svc",
Namespace: "wrong-ns",
},
Spec: v1.ServiceSpec{
Selector: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
},
},
selectorLabels: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
expectedErr: true,
},
{
name: "custom svc doesn't exist",
selectorLabels: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
expectedErr: true,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
p := makeBarebonesPrometheus(name, ns)
p.Spec.ServiceName = &serviceName
clientSet := fake.NewSimpleClientset(&tc.service)
svcClient := clientSet.CoreV1().Services(ns)
err := EnsureCustomGoverningService(context.Background(), p.Namespace, *p.Spec.ServiceName, svcClient, tc.selectorLabels)
if tc.expectedErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
func makeBarebonesPrometheus(name, ns string) *monitoringv1.Prometheus {
return &monitoringv1.Prometheus{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: ns,
Annotations: map[string]string{},
},
Spec: monitoringv1.PrometheusSpec{
CommonPrometheusFields: monitoringv1.CommonPrometheusFields{
Replicas: ptr.To(int32(1)),
},
},
}
}

View file

@ -797,24 +797,33 @@ func (c *Operator) sync(ctx context.Context, key string) error {
return fmt.Errorf("failed to reconcile Thanos config secret: %w", err)
}
// Reconcile the governing service.
svc := prompkg.BuildStatefulSetService(
governingServiceName,
map[string]string{"app.kubernetes.io/name": "prometheus"},
p,
c.config,
)
if p.Spec.ServiceName != nil {
svcClient := c.kclient.CoreV1().Services(p.Namespace)
selectorLabels := makeSelectorLabels(p.Name)
if p.Spec.Thanos != nil {
svc.Spec.Ports = append(svc.Spec.Ports, v1.ServicePort{
Name: "grpc",
Port: 10901,
TargetPort: intstr.FromString("grpc"),
})
}
if err := prompkg.EnsureCustomGoverningService(ctx, p.Namespace, *p.Spec.ServiceName, svcClient, selectorLabels); err != nil {
return err
}
} else {
// Reconcile the default governing service.
svc := prompkg.BuildStatefulSetService(
governingServiceName,
map[string]string{"app.kubernetes.io/name": "prometheus"},
p,
c.config,
)
if _, err := k8sutil.CreateOrUpdateService(ctx, c.kclient.CoreV1().Services(p.Namespace), svc); err != nil {
return fmt.Errorf("synchronizing governing service failed: %w", err)
if p.Spec.Thanos != nil {
svc.Spec.Ports = append(svc.Spec.Ports, v1.ServicePort{
Name: "grpc",
Port: 10901,
TargetPort: intstr.FromString("grpc"),
})
}
if _, err := k8sutil.CreateOrUpdateService(ctx, c.kclient.CoreV1().Services(p.Namespace), svc); err != nil {
return fmt.Errorf("synchronizing default governing service failed: %w", err)
}
}
ssetClient := c.kclient.AppsV1().StatefulSets(p.Namespace)

View file

@ -304,6 +304,8 @@ func testAllNSPrometheus(t *testing.T) {
"PrometheusAgentStatusScale": testPrometheusAgentStatusScale,
"PrometheusStatusScale": testPrometheusStatusScale,
"ScrapeConfigCRDValidations": testScrapeConfigCRDValidations,
"PrometheusServiceName": testPrometheusServiceName,
"PrometheusAgentSSetServiceName": testPrometheusAgentSSetServiceName,
}
for name, f := range testFuncs {

View file

@ -5300,6 +5300,57 @@ func testPrometheusStatusScale(t *testing.T) {
}
}
func testPrometheusServiceName(t *testing.T) {
t.Parallel()
testCtx := framework.NewTestCtx(t)
defer testCtx.Cleanup(t)
ns := framework.CreateNamespace(context.Background(), t, testCtx)
name := "test-servicename"
svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-service", name),
Namespace: ns,
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
Ports: []v1.ServicePort{
{
Name: "web",
Port: 9090,
},
},
Selector: map[string]string{
"prometheus": name,
"app.kubernetes.io/name": "prometheus",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
},
}
_, err := framework.KubeClient.CoreV1().Services(ns).Create(context.Background(), svc, metav1.CreateOptions{})
require.NoError(t, err)
framework.SetupPrometheusRBAC(context.Background(), t, testCtx, ns)
p := framework.MakeBasicPrometheus(ns, name, name, 1)
p.Spec.ServiceName = &svc.Name
_, err = framework.CreatePrometheusAndWaitUntilReady(context.Background(), ns, p)
require.NoError(t, err)
targets, err := framework.GetActiveTargets(context.Background(), ns, svc.Name)
require.NoError(t, err)
require.Empty(t, targets)
// Ensure that the default governing service was not created by the operator.
svcList, err := framework.KubeClient.CoreV1().Services(ns).List(context.Background(), metav1.ListOptions{})
require.NoError(t, err)
require.Len(t, svcList.Items, 1)
require.Equal(t, svcList.Items[0].Name, svc.Name)
}
func isAlertmanagerDiscoveryWorking(ns, promSVCName, alertmanagerName string) func(ctx context.Context) (bool, error) {
return func(ctx context.Context) (bool, error) {
pods, err := framework.KubeClient.CoreV1().Pods(ns).List(ctx, alertmanager.ListOptions(alertmanagerName))

View file

@ -576,6 +576,57 @@ func testPrometheusAgentDaemonSetSelectPodMonitor(t *testing.T) {
require.NotEqual(t, firstTargetIP, secondTargetIP)
}
func testPrometheusAgentSSetServiceName(t *testing.T) {
t.Parallel()
testCtx := framework.NewTestCtx(t)
defer testCtx.Cleanup(t)
ns := framework.CreateNamespace(context.Background(), t, testCtx)
name := "test-agent-servicename"
svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-service", name),
Namespace: ns,
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
Ports: []v1.ServicePort{
{
Name: "web",
Port: 9090,
},
},
Selector: map[string]string{
"app.kubernetes.io/name": "prometheus-agent",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "prometheus-operator",
},
},
}
_, err := framework.KubeClient.CoreV1().Services(ns).Create(context.Background(), svc, metav1.CreateOptions{})
require.NoError(t, err)
framework.SetupPrometheusRBAC(context.Background(), t, testCtx, ns)
p := framework.MakeBasicPrometheusAgent(ns, name, name, 1)
p.Spec.ServiceName = &svc.Name
_, err = framework.CreatePrometheusAgentAndWaitUntilReady(context.Background(), ns, p)
require.NoError(t, err)
targets, err := framework.GetActiveTargets(context.Background(), ns, svc.Name)
require.NoError(t, err)
require.Empty(t, targets)
// Ensure that the default governing service was not created by the operator.
svcList, err := framework.KubeClient.CoreV1().Services(ns).List(context.Background(), metav1.ListOptions{})
require.NoError(t, err)
require.Len(t, svcList.Items, 1)
require.Equal(t, svcList.Items[0].Name, svc.Name)
}
type Target struct {
Labels struct {
Instance string `json:"instance"`