Skip to content

Commit 648c091

Browse files
authored
feat: discover default lokistack (#690)
1 parent 5790aea commit 648c091

11 files changed

+227
-137
lines changed

bundle/manifests/observability-operator.clusterserviceversion.yaml

+8-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ metadata:
4242
categories: Monitoring
4343
certified: "false"
4444
containerImage: observability-operator:1.0.0
45-
createdAt: "2025-02-24T18:08:14Z"
45+
createdAt: "2025-03-03T08:38:22Z"
4646
description: A Go based Kubernetes operator to setup and manage highly available
4747
Monitoring Stack using Prometheus, Alertmanager and Thanos Querier.
4848
operatorframework.io/cluster-monitoring: "true"
@@ -415,6 +415,13 @@ spec:
415415
- network
416416
verbs:
417417
- get
418+
- apiGroups:
419+
- loki.grafana.com
420+
resources:
421+
- lokistacks
422+
verbs:
423+
- get
424+
- list
418425
- apiGroups:
419426
- monitoring.coreos.com
420427
resourceNames:

bundle/manifests/observability.openshift.io_uiplugins.yaml

+2-7
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,9 @@ spec:
123123
properties:
124124
name:
125125
description: Name of the LokiStack resource.
126-
minLength: 1
127126
type: string
128-
required:
129-
- name
127+
namespace:
128+
type: string
130129
type: object
131130
x-kubernetes-map-type: atomic
132131
timeout:
@@ -137,8 +136,6 @@ spec:
137136
or 'm' (minutes). If the unit is omitted, it defaults to seconds.
138137
pattern: ^([0-9]+)([sm]{0,1})$
139138
type: string
140-
required:
141-
- lokiStack
142139
type: object
143140
monitoring:
144141
description: Monitoring contains configuration for the monitoring
@@ -233,8 +230,6 @@ spec:
233230
- message: Distributed Tracing configuration is only supported with the
234231
DistributedTracing type
235232
rule: self.type == 'DistributedTracing' || !has(self.distributedTracing)
236-
- message: Logging configuration is required if type is Logging
237-
rule: self.type != 'Logging' || has(self.logging)
238233
status:
239234
description: |-
240235
UIPluginStatus defines the observed state of UIPlugin.

deploy/crds/common/observability.openshift.io_uiplugins.yaml

+2-7
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,9 @@ spec:
123123
properties:
124124
name:
125125
description: Name of the LokiStack resource.
126-
minLength: 1
127126
type: string
128-
required:
129-
- name
127+
namespace:
128+
type: string
130129
type: object
131130
x-kubernetes-map-type: atomic
132131
timeout:
@@ -137,8 +136,6 @@ spec:
137136
or 'm' (minutes). If the unit is omitted, it defaults to seconds.
138137
pattern: ^([0-9]+)([sm]{0,1})$
139138
type: string
140-
required:
141-
- lokiStack
142139
type: object
143140
monitoring:
144141
description: Monitoring contains configuration for the monitoring
@@ -233,8 +230,6 @@ spec:
233230
- message: Distributed Tracing configuration is only supported with the
234231
DistributedTracing type
235232
rule: self.type == 'DistributedTracing' || !has(self.distributedTracing)
236-
- message: Logging configuration is required if type is Logging
237-
rule: self.type != 'Logging' || has(self.logging)
238233
status:
239234
description: |-
240235
UIPluginStatus defines the observed state of UIPlugin.

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

+7
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ rules:
130130
- network
131131
verbs:
132132
- get
133+
- apiGroups:
134+
- loki.grafana.com
135+
resources:
136+
- lokistacks
137+
verbs:
138+
- get
139+
- list
133140
- apiGroups:
134141
- monitoring.coreos.com
135142
resourceNames:

docs/api.md

+16-9
Original file line numberDiff line numberDiff line change
@@ -4262,14 +4262,6 @@ It only applies to UIPlugin Type: Logging.
42624262
</tr>
42634263
</thead>
42644264
<tbody><tr>
4265-
<td><b><a href="#uipluginspeclogginglokistack">lokiStack</a></b></td>
4266-
<td>object</td>
4267-
<td>
4268-
LokiStack points to the LokiStack instance of which logs should be displayed.
4269-
It always references a LokiStack in the "openshift-logging" namespace.<br/>
4270-
</td>
4271-
<td>true</td>
4272-
</tr><tr>
42734265
<td><b>logsLimit</b></td>
42744266
<td>integer</td>
42754267
<td>
@@ -4279,6 +4271,14 @@ It always references a LokiStack in the "openshift-logging" namespace.<br/>
42794271
<i>Minimum</i>: 0<br/>
42804272
</td>
42814273
<td>false</td>
4274+
</tr><tr>
4275+
<td><b><a href="#uipluginspeclogginglokistack">lokiStack</a></b></td>
4276+
<td>object</td>
4277+
<td>
4278+
LokiStack points to the LokiStack instance of which logs should be displayed.
4279+
It always references a LokiStack in the "openshift-logging" namespace.<br/>
4280+
</td>
4281+
<td>false</td>
42824282
</tr><tr>
42834283
<td><b>timeout</b></td>
42844284
<td>string</td>
@@ -4316,7 +4316,14 @@ It always references a LokiStack in the "openshift-logging" namespace.
43164316
<td>
43174317
Name of the LokiStack resource.<br/>
43184318
</td>
4319-
<td>true</td>
4319+
<td>false</td>
4320+
</tr><tr>
4321+
<td><b>namespace</b></td>
4322+
<td>string</td>
4323+
<td>
4324+
<br/>
4325+
</td>
4326+
<td>false</td>
43204327
</tr></tbody>
43214328
</table>
43224329

pkg/apis/uiplugin/v1alpha1/types.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ type LoggingConfig struct {
102102
// LokiStack points to the LokiStack instance of which logs should be displayed.
103103
// It always references a LokiStack in the "openshift-logging" namespace.
104104
//
105-
// +kubebuilder:validation:Required
106-
LokiStack LokiStackReference `json:"lokiStack"`
105+
// +kubebuilder:validation:Optional
106+
LokiStack *LokiStackReference `json:"lokiStack"`
107107

108108
// LogsLimit is the max number of entries returned for a query.
109109
//
@@ -130,9 +130,11 @@ type LoggingConfig struct {
130130
type LokiStackReference struct {
131131
// Name of the LokiStack resource.
132132
//
133-
// +kubebuilder:validation:Required
134-
// +kubebuilder:validation:MinLength:=1
135-
Name string `json:"name"`
133+
// +kubebuilder:validation:Optional
134+
Name string `json:"name,omitempty"`
135+
136+
// +kubebuilder:validation:Optional
137+
Namespace string `json:"namespace,omitempty"`
136138
}
137139

138140
// MonitoringConfig contains options for configuring the monitoring console plugin.
@@ -214,7 +216,6 @@ type IncidentsReference struct {
214216
//
215217
// +kubebuilder:validation:XValidation:rule="self.type == 'TroubleshootingPanel' || !has(self.troubleshootingPanel)", message="Troubleshooting Panel configuration is only supported with the TroubleshootingPanel type"
216218
// +kubebuilder:validation:XValidation:rule="self.type == 'DistributedTracing' || !has(self.distributedTracing)", message="Distributed Tracing configuration is only supported with the DistributedTracing type"
217-
// +kubebuilder:validation:XValidation:rule="self.type != 'Logging' || has(self.logging)", message="Logging configuration is required if type is Logging"
218219
type UIPluginSpec struct {
219220
// Type defines the UI plugin.
220221
// +required

pkg/apis/uiplugin/v1alpha1/zz_generated.deepcopy.go

+6-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controllers/uiplugin/controller.go

+22-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1919
"k8s.io/apimachinery/pkg/runtime"
2020
"k8s.io/apimachinery/pkg/types"
21+
"k8s.io/client-go/dynamic"
2122
ctrl "sigs.k8s.io/controller-runtime"
2223
"sigs.k8s.io/controller-runtime/pkg/builder"
2324
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -30,12 +31,13 @@ import (
3031
)
3132

3233
type resourceManager struct {
33-
k8sClient client.Client
34-
scheme *runtime.Scheme
35-
logger logr.Logger
36-
controller controller.Controller
37-
pluginConf UIPluginsConfiguration
38-
clusterVersion string
34+
k8sClient client.Client
35+
k8sDynamicClient dynamic.Interface
36+
scheme *runtime.Scheme
37+
logger logr.Logger
38+
controller controller.Controller
39+
pluginConf UIPluginsConfiguration
40+
clusterVersion string
3941
}
4042

4143
type UIPluginsConfiguration struct {
@@ -76,6 +78,7 @@ const (
7678

7779
// RBAC for logging view plugin
7880
// +kubebuilder:rbac:groups=loki.grafana.com,resources=application;infrastructure;audit,verbs=get
81+
// +kubebuilder:rbac:groups=loki.grafana.com,resources=lokistacks,verbs=list;get
7982

8083
// RBAC for perses
8184
// +kubebuilder:rbac:groups=perses.dev,resources=perses;persesdatasources;persesdashboards,verbs=get;list;watch;create;update;delete;patch
@@ -113,12 +116,19 @@ func RegisterWithManager(mgr ctrl.Manager, opts Options) error {
113116
return err
114117
}
115118

119+
dynamicClient, err := dynamic.NewForConfig(mgr.GetConfig())
120+
if err != nil {
121+
logger.Error(err, "failed to create dynamic client")
122+
return err
123+
}
124+
116125
rm := &resourceManager{
117-
k8sClient: mgr.GetClient(),
118-
scheme: mgr.GetScheme(),
119-
logger: logger,
120-
pluginConf: opts.PluginsConf,
121-
clusterVersion: clusterVersion.Status.Desired.Version,
126+
k8sClient: mgr.GetClient(),
127+
k8sDynamicClient: dynamicClient,
128+
scheme: mgr.GetScheme(),
129+
logger: logger,
130+
pluginConf: opts.PluginsConf,
131+
clusterVersion: clusterVersion.Status.Desired.Version,
122132
}
123133

124134
generationChanged := builder.WithPredicates(predicate.GenerationChangedPredicate{})
@@ -247,7 +257,7 @@ func (rm resourceManager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
247257
return ctrl.Result{}, err
248258
}
249259

250-
pluginInfo, err := PluginInfoBuilder(ctx, rm.k8sClient, plugin, rm.pluginConf, compatibilityInfo, rm.clusterVersion)
260+
pluginInfo, err := PluginInfoBuilder(ctx, rm.k8sClient, rm.k8sDynamicClient, plugin, rm.pluginConf, compatibilityInfo, rm.clusterVersion)
251261

252262
if err != nil {
253263
logger.Error(err, "failed to reconcile plugin")
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package uiplugin
2+
3+
import (
4+
osv1 "github.com/openshift/api/console/v1"
5+
osv1alpha1 "github.com/openshift/api/console/v1alpha1"
6+
corev1 "k8s.io/api/core/v1"
7+
rbacv1 "k8s.io/api/rbac/v1"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
10+
uiv1alpha1 "github.com/rhobs/observability-operator/pkg/apis/uiplugin/v1alpha1"
11+
)
12+
13+
func createDashboardsPluginInfo(plugin *uiv1alpha1.UIPlugin, namespace, name, image string) (*UIPluginInfo, error) {
14+
pluginName := "observability-ui-" + name
15+
readerRoleName := plugin.Name + "-datasource-reader"
16+
datasourcesNamespace := "openshift-config-managed"
17+
18+
return &UIPluginInfo{
19+
Image: image,
20+
Name: pluginName,
21+
ConsoleName: pluginTypeToConsoleName[plugin.Spec.Type],
22+
DisplayName: "Console Enhanced Dashboards",
23+
ResourceNamespace: namespace,
24+
LegacyProxies: []osv1alpha1.ConsolePluginProxy{
25+
{
26+
Type: osv1alpha1.ProxyTypeService,
27+
Alias: "backend",
28+
Authorize: true,
29+
Service: osv1alpha1.ConsolePluginProxyServiceConfig{
30+
Name: pluginName,
31+
Namespace: namespace,
32+
Port: port,
33+
},
34+
},
35+
},
36+
Proxies: []osv1.ConsolePluginProxy{
37+
{
38+
Alias: "backend",
39+
Authorization: "UserToken",
40+
Endpoint: osv1.ConsolePluginProxyEndpoint{
41+
Type: osv1.ProxyTypeService,
42+
Service: &osv1.ConsolePluginProxyServiceConfig{
43+
Name: pluginName,
44+
Namespace: namespace,
45+
Port: port,
46+
},
47+
},
48+
},
49+
},
50+
Role: &rbacv1.Role{
51+
TypeMeta: metav1.TypeMeta{
52+
APIVersion: rbacv1.SchemeGroupVersion.String(),
53+
Kind: "Role",
54+
},
55+
ObjectMeta: metav1.ObjectMeta{
56+
Name: readerRoleName,
57+
Namespace: datasourcesNamespace,
58+
},
59+
Rules: []rbacv1.PolicyRule{
60+
{
61+
APIGroups: []string{""},
62+
Resources: []string{"configmaps"},
63+
Verbs: []string{"get", "list", "watch"},
64+
},
65+
},
66+
},
67+
RoleBinding: &rbacv1.RoleBinding{
68+
TypeMeta: metav1.TypeMeta{
69+
APIVersion: rbacv1.SchemeGroupVersion.String(),
70+
Kind: "RoleBinding",
71+
},
72+
ObjectMeta: metav1.ObjectMeta{
73+
Name: pluginName + "-rolebinding",
74+
Namespace: datasourcesNamespace,
75+
},
76+
Subjects: []rbacv1.Subject{
77+
{
78+
APIGroup: corev1.SchemeGroupVersion.Group,
79+
Kind: "ServiceAccount",
80+
Name: pluginName + serviceAccountSuffix,
81+
Namespace: namespace,
82+
},
83+
},
84+
RoleRef: rbacv1.RoleRef{
85+
APIGroup: rbacv1.SchemeGroupVersion.Group,
86+
Kind: "Role",
87+
Name: readerRoleName,
88+
},
89+
},
90+
}, nil
91+
}

0 commit comments

Comments
 (0)