Skip to content

Commit 5bcf2db

Browse files
authored
feat: add Incidents backend (#678)
* feat: add Incidents backend Signed-off-by: Alberto Falossi <afalossi@redhat.com> * chore: update manifests Signed-off-by: Alberto Falossi <afalossi@redhat.com> * chore: pin health-analyzer to v0.3.0 Signed-off-by: Alberto Falossi <afalossi@redhat.com> --------- Signed-off-by: Alberto Falossi <afalossi@redhat.com>
1 parent da746a6 commit 5bcf2db

File tree

9 files changed

+339
-32
lines changed

9 files changed

+339
-32
lines changed

bundle/manifests/observability-operator.clusterserviceversion.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,18 @@ spec:
338338
- patch
339339
- update
340340
- watch
341+
- apiGroups:
342+
- authentication.k8s.io
343+
resources:
344+
- tokenreviews
345+
verbs:
346+
- create
347+
- apiGroups:
348+
- authorization.k8s.io
349+
resources:
350+
- subjectaccessreviews
351+
verbs:
352+
- create
341353
- apiGroups:
342354
- autoscaling
343355
resources:
@@ -419,6 +431,7 @@ spec:
419431
verbs:
420432
- create
421433
- delete
434+
- get
422435
- list
423436
- patch
424437
- update

cmd/operator/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var defaultImages = map[string]string{
4545
"ui-logging": "quay.io/openshift-observability-ui/logging-view-plugin:v6.0.0",
4646
"ui-monitoring": "quay.io/openshift-observability-ui/monitoring-console-plugin:latest",
4747
"korrel8r": "quay.io/korrel8r/korrel8r:0.7.4",
48+
"health-analyzer": "quay.io/openshiftanalytics/cluster-health-analyzer:v0.3.0",
4849
}
4950

5051
func imagesUsed() []string {

deploy/operator/observability-operator-cluster-role.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ rules:
6363
- patch
6464
- update
6565
- watch
66+
- apiGroups:
67+
- authentication.k8s.io
68+
resources:
69+
- tokenreviews
70+
verbs:
71+
- create
72+
- apiGroups:
73+
- authorization.k8s.io
74+
resources:
75+
- subjectaccessreviews
76+
verbs:
77+
- create
6678
- apiGroups:
6779
- autoscaling
6880
resources:
@@ -144,6 +156,7 @@ rules:
144156
verbs:
145157
- create
146158
- delete
159+
- get
147160
- list
148161
- patch
149162
- update

pkg/controllers/uiplugin/components.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,45 @@ func pluginComponentReconcilers(plugin *uiv1alpha1.UIPlugin, pluginInfo UIPlugin
110110
}
111111
}
112112

113+
if pluginInfo.HealthAnalyzerImage != "" {
114+
serviceAccountName := plugin.Name + serviceAccountSuffix
115+
components = append(components, reconciler.NewUpdater(newClusterRoleBinding(namespace, serviceAccountName, "cluster-monitoring-view", "cluster-monitoring-view"), plugin))
116+
components = append(components, reconciler.NewUpdater(newClusterRoleBinding(namespace, serviceAccountName, "system:auth-delegator", serviceAccountName+":system:auth-delegator"), plugin))
117+
components = append(components, reconciler.NewUpdater(newHealthAnalyzerPrometheusRole(namespace), plugin))
118+
components = append(components, reconciler.NewUpdater(newHealthAnalyzerPrometheusRoleBinding(namespace), plugin))
119+
components = append(components, reconciler.NewUpdater(newHealthAnalyzerService(namespace), plugin))
120+
components = append(components, reconciler.NewUpdater(newHealthAnalyzerDeployment(namespace, serviceAccountName, pluginInfo), plugin))
121+
components = append(components, reconciler.NewUpdater(newHealthAnalyzerServiceMonitor(namespace), plugin))
122+
}
123+
113124
return components
114125
}
115126

127+
func newClusterRoleBinding(namespace string, serviceAccountName string, roleName string, name string) *rbacv1.ClusterRoleBinding {
128+
return &rbacv1.ClusterRoleBinding{
129+
TypeMeta: metav1.TypeMeta{
130+
APIVersion: rbacv1.SchemeGroupVersion.String(),
131+
Kind: "ClusterRoleBinding",
132+
},
133+
ObjectMeta: metav1.ObjectMeta{
134+
Name: name,
135+
},
136+
Subjects: []rbacv1.Subject{
137+
{
138+
APIGroup: corev1.SchemeGroupVersion.Group,
139+
Kind: "ServiceAccount",
140+
Name: serviceAccountName,
141+
Namespace: namespace,
142+
},
143+
},
144+
RoleRef: rbacv1.RoleRef{
145+
APIGroup: rbacv1.SchemeGroupVersion.Group,
146+
Kind: "ClusterRole",
147+
Name: roleName,
148+
},
149+
}
150+
}
151+
116152
func newServiceAccount(info UIPluginInfo, namespace string) *corev1.ServiceAccount {
117153
return &corev1.ServiceAccount{
118154
TypeMeta: metav1.TypeMeta{

pkg/controllers/uiplugin/controller.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ const (
8989
//+kubebuilder:rbac:groups=monitoring.coreos.com,resources=prometheuses/api,resourceNames=k8s,verbs=get;create;update
9090
//+kubebuilder:rbac:groups=monitoring.coreos.com,resources=alertmanagers/api,resourceNames=main,verbs=get;list
9191

92+
// RBAC for Health Analyzer
93+
//+kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create
94+
//+kubebuilder:rbac:groups=authorization.k8s.io,resources=subjectaccessreviews,verbs=create
95+
//+kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors,verbs=get;create;update;patch;delete
96+
9297
const finalizerName = "uiplugin.observability.openshift.io/finalizer"
9398

9499
// RegisterWithManager registers the controller with Manager
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
package uiplugin
2+
3+
import (
4+
monv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
5+
appsv1 "k8s.io/api/apps/v1"
6+
corev1 "k8s.io/api/core/v1"
7+
rbacv1 "k8s.io/api/rbac/v1"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/apimachinery/pkg/util/intstr"
10+
"k8s.io/utils/ptr"
11+
)
12+
13+
const (
14+
name = "health-analyzer"
15+
volumeMountName = name + "-tls"
16+
)
17+
18+
func newHealthAnalyzerPrometheusRole(namespace string) *rbacv1.Role {
19+
role := &rbacv1.Role{
20+
TypeMeta: metav1.TypeMeta{
21+
APIVersion: rbacv1.SchemeGroupVersion.String(),
22+
Kind: "Role",
23+
},
24+
ObjectMeta: metav1.ObjectMeta{
25+
Name: "prometheus-k8s",
26+
Namespace: namespace,
27+
},
28+
Rules: []rbacv1.PolicyRule{
29+
{
30+
APIGroups: []string{""},
31+
Resources: []string{"services", "endpoints", "pods"},
32+
Verbs: []string{"get", "list", "watch"},
33+
},
34+
},
35+
}
36+
return role
37+
}
38+
39+
func newHealthAnalyzerPrometheusRoleBinding(namespace string) *rbacv1.RoleBinding {
40+
roleBinding := &rbacv1.RoleBinding{
41+
TypeMeta: metav1.TypeMeta{
42+
APIVersion: rbacv1.SchemeGroupVersion.String(),
43+
Kind: "RoleBinding",
44+
},
45+
ObjectMeta: metav1.ObjectMeta{
46+
Name: "prometheus-k8s",
47+
Namespace: namespace,
48+
},
49+
RoleRef: rbacv1.RoleRef{
50+
APIGroup: rbacv1.SchemeGroupVersion.Group,
51+
Kind: "Role",
52+
Name: "prometheus-k8s",
53+
},
54+
Subjects: []rbacv1.Subject{
55+
{
56+
Kind: "ServiceAccount",
57+
Name: "prometheus-k8s",
58+
Namespace: "openshift-monitoring",
59+
},
60+
},
61+
}
62+
return roleBinding
63+
}
64+
65+
func newHealthAnalyzerService(namespace string) *corev1.Service {
66+
service := &corev1.Service{
67+
TypeMeta: metav1.TypeMeta{
68+
APIVersion: corev1.SchemeGroupVersion.String(),
69+
Kind: "Service",
70+
},
71+
ObjectMeta: metav1.ObjectMeta{
72+
Name: name,
73+
Namespace: namespace,
74+
Annotations: map[string]string{
75+
"service.beta.openshift.io/serving-cert-secret-name": volumeMountName,
76+
},
77+
Labels: componentLabels(name),
78+
},
79+
Spec: corev1.ServiceSpec{
80+
Ports: []corev1.ServicePort{
81+
{
82+
Name: "metrics",
83+
Port: 8443,
84+
TargetPort: intstr.FromString("metrics"),
85+
},
86+
},
87+
Selector: map[string]string{
88+
"app.kubernetes.io/instance": name,
89+
},
90+
Type: corev1.ServiceTypeClusterIP,
91+
},
92+
}
93+
94+
return service
95+
}
96+
97+
func newHealthAnalyzerDeployment(namespace string, serviceAccountName string, pluginInfo UIPluginInfo) *appsv1.Deployment {
98+
deploy := &appsv1.Deployment{
99+
TypeMeta: metav1.TypeMeta{
100+
APIVersion: appsv1.SchemeGroupVersion.String(),
101+
Kind: "Deployment",
102+
},
103+
ObjectMeta: metav1.ObjectMeta{
104+
Name: name,
105+
Namespace: namespace,
106+
Labels: componentLabels(name),
107+
},
108+
Spec: appsv1.DeploymentSpec{
109+
Replicas: ptr.To(int32(1)),
110+
Selector: &metav1.LabelSelector{
111+
MatchLabels: map[string]string{
112+
"app.kubernetes.io/instance": name,
113+
},
114+
},
115+
Template: corev1.PodTemplateSpec{
116+
ObjectMeta: metav1.ObjectMeta{
117+
Labels: componentLabels(name),
118+
},
119+
Spec: corev1.PodSpec{
120+
ServiceAccountName: serviceAccountName,
121+
AutomountServiceAccountToken: ptr.To(true),
122+
Containers: []corev1.Container{
123+
{
124+
Name: name,
125+
Image: pluginInfo.HealthAnalyzerImage,
126+
ImagePullPolicy: corev1.PullAlways,
127+
Args: []string{
128+
"--tls-cert-file=/etc/tls/private/tls.crt",
129+
"--tls-private-key-file=/etc/tls/private/tls.key",
130+
},
131+
Env: []corev1.EnvVar{
132+
{
133+
Name: "PROM_URL",
134+
Value: "https://thanos-querier.openshift-monitoring.svc.cluster.local:9091/",
135+
},
136+
},
137+
SecurityContext: &corev1.SecurityContext{
138+
RunAsNonRoot: ptr.To(true),
139+
AllowPrivilegeEscalation: ptr.To(false),
140+
Capabilities: &corev1.Capabilities{
141+
Drop: []corev1.Capability{"ALL"},
142+
},
143+
SeccompProfile: &corev1.SeccompProfile{
144+
Type: corev1.SeccompProfileTypeRuntimeDefault,
145+
},
146+
},
147+
Ports: []corev1.ContainerPort{
148+
{
149+
ContainerPort: 8443,
150+
Name: "metrics",
151+
},
152+
},
153+
TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
154+
VolumeMounts: []corev1.VolumeMount{
155+
{
156+
MountPath: "/etc/tls/private",
157+
Name: volumeMountName,
158+
ReadOnly: true,
159+
},
160+
},
161+
},
162+
},
163+
Volumes: []corev1.Volume{
164+
{
165+
Name: volumeMountName,
166+
VolumeSource: corev1.VolumeSource{
167+
Secret: &corev1.SecretVolumeSource{
168+
SecretName: volumeMountName,
169+
},
170+
},
171+
},
172+
},
173+
},
174+
},
175+
},
176+
}
177+
return deploy
178+
}
179+
180+
func newHealthAnalyzerServiceMonitor(namespace string) *monv1.ServiceMonitor {
181+
serviceMonitor := &monv1.ServiceMonitor{
182+
TypeMeta: metav1.TypeMeta{
183+
APIVersion: monv1.SchemeGroupVersion.String(),
184+
Kind: "ServiceMonitor",
185+
},
186+
ObjectMeta: metav1.ObjectMeta{
187+
Name: name,
188+
Namespace: namespace,
189+
},
190+
Spec: monv1.ServiceMonitorSpec{
191+
Endpoints: []monv1.Endpoint{
192+
{
193+
Interval: "30s",
194+
Port: "metrics",
195+
Scheme: "https",
196+
TLSConfig: &monv1.TLSConfig{
197+
SafeTLSConfig: monv1.SafeTLSConfig{
198+
ServerName: ptr.To(name + "." + namespace + ".svc"),
199+
},
200+
CAFile: "/etc/prometheus/configmaps/serving-certs-ca-bundle/service-ca.crt",
201+
CertFile: "/etc/prometheus/secrets/metrics-client-certs/tls.crt",
202+
KeyFile: "/etc/prometheus/secrets/metrics-client-certs/tls.key",
203+
},
204+
},
205+
},
206+
Selector: metav1.LabelSelector{
207+
MatchLabels: map[string]string{
208+
"app.kubernetes.io/instance": name,
209+
},
210+
},
211+
},
212+
}
213+
214+
return serviceMonitor
215+
}

pkg/controllers/uiplugin/monitoring.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ func addAcmAlertingProxy(pluginInfo *UIPluginInfo, name string, namespace string
181181
)
182182
}
183183

184-
func createMonitoringPluginInfo(plugin *uiv1alpha1.UIPlugin, namespace, name, image string, features []string, clusterVersion string) (*UIPluginInfo, error) {
184+
func createMonitoringPluginInfo(plugin *uiv1alpha1.UIPlugin, namespace, name, image string, features []string, clusterVersion string, healthAnalyzerImage string) (*UIPluginInfo, error) {
185185
config := plugin.Spec.Monitoring
186186
if config == nil {
187187
return nil, fmt.Errorf("monitoring configuration can not be empty for plugin type %s", plugin.Spec.Type)
@@ -211,6 +211,7 @@ func createMonitoringPluginInfo(plugin *uiv1alpha1.UIPlugin, namespace, name, im
211211
features = append(features, "perses-dashboards")
212212
}
213213
if isValidIncidentsConfig {
214+
pluginInfo.HealthAnalyzerImage = healthAnalyzerImage
214215
features = append(features, "incidents")
215216
}
216217
addFeatureFlags(pluginInfo, features)

0 commit comments

Comments
 (0)