Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Korrel8r backend creation when the troubleshooting panel is deployed #497

Merged
merged 1 commit into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions bundle/manifests/observability.openshift.io_uiplugins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,6 @@ spec:
description: TroubleshootingPanel contains configuration for the troubleshooting
console plugin.
properties:
korrel8r:
description: korrel8r defines the Korrel8r instance that the troubleshooting
panel plugin will connect to
properties:
name:
description: Name of the korrel8r instance
type: string
namespace:
description: Namespace of the korrel8r instance
type: string
type: object
timeout:
description: |-
Timeout is the maximum duration before a query timeout.
Expand Down
1 change: 1 addition & 0 deletions cmd/operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var defaultImages = map[string]string{
"ui-troubleshooting-panel": "quay.io/openshift-observability-ui/troubleshooting-panel-console-plugin:v0.1.0",
"ui-distributed-tracing": "quay.io/openshift-observability-ui/distributed-tracing-console-plugin:v0.1.0",
"ui-logging": "quay.io/openshift-logging/logging-view-plugin:6.0.0",
"korrel8r": "quay.io/korrel8r/korrel8r:0.6.5",
}

func imagesUsed() []string {
Expand Down
11 changes: 0 additions & 11 deletions deploy/crds/common/observability.openshift.io_uiplugins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,6 @@ spec:
description: TroubleshootingPanel contains configuration for the troubleshooting
console plugin.
properties:
korrel8r:
description: korrel8r defines the Korrel8r instance that the troubleshooting
panel plugin will connect to
properties:
name:
description: Name of the korrel8r instance
type: string
namespace:
description: Namespace of the korrel8r instance
type: string
type: object
timeout:
description: |-
Timeout is the maximum duration before a query timeout.
Expand Down
41 changes: 0 additions & 41 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3124,13 +3124,6 @@ TroubleshootingPanel contains configuration for the troubleshooting console plug
</tr>
</thead>
<tbody><tr>
<td><b><a href="#uipluginspectroubleshootingpanelkorrel8r">korrel8r</a></b></td>
<td>object</td>
<td>
korrel8r defines the Korrel8r instance that the troubleshooting panel plugin will connect to<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>timeout</b></td>
<td>string</td>
<td>
Expand All @@ -3145,40 +3138,6 @@ or 'm' (minutes).<br/>
</table>


### UIPlugin.spec.troubleshootingPanel.korrel8r
<sup><sup>[↩ Parent](#uipluginspectroubleshootingpanel)</sup></sup>



korrel8r defines the Korrel8r instance that the troubleshooting panel plugin will connect to

<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>name</b></td>
<td>string</td>
<td>
Name of the korrel8r instance<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>namespace</b></td>
<td>string</td>
<td>
Namespace of the korrel8r instance<br/>
</td>
<td>false</td>
</tr></tbody>
</table>


### UIPlugin.status
<sup><sup>[↩ Parent](#uiplugin)</sup></sup>

Expand Down
2 changes: 1 addition & 1 deletion docs/user-guides/observability-ui-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ spec:

### Troubleshooting Panel

The plugin will connect to a Korrel8r instance named `korrel8r` in the `korrel8r` namespace. A "Troubleshooting Panel" button is added to the alerts page, which will convert the current alert into a Korrel8r query, then retrieve related neighbors and display them in a topology view.
The plugin will connect to a Korrel8r service named `korrel8r` in the namespace where the observability operator(and Korrel8r) is deployed. A "Troubleshooting Panel" button is added to the alerts page, which will convert the current alert into a Korrel8r query, then retrieve related neighbors and display them in a topology view.

To enable the troubleshooting panel console plugin, create a `UIPlugin` CR. The following example shows how to create a CR to enable the troubleshooting panel console plugin:

Expand Down
19 changes: 0 additions & 19 deletions pkg/apis/uiplugin/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,6 @@ type TroubleshootingPanelConfig struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OCP Console Query Timeout",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:ocpConsoleTimeout"}
// +kubebuilder:validation:Pattern:="^([0-9]+)([sm]{1})$"
Timeout string `json:"timeout,omitempty"`
// korrel8r defines the Korrel8r instance that the troubleshooting panel plugin will connect to
//
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Korrel8r Instance"
Korrel8r TroubleshootingPanelKorrel8rConfig `json:"korrel8r,omitempty"`
}

type TroubleshootingPanelKorrel8rConfig struct {
// Name of the korrel8r instance
//
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Korrel8r Instance Name"
Name string `json:"name,omitempty"`

// Namespace of the korrel8r instance
//
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Korrel8r Instance Namespace"
Namespace string `json:"namespace,omitempty"`
}

// DistributedTracingConfig contains options for configuring the Distributed Tracing plugin
Expand Down
16 changes: 0 additions & 16 deletions pkg/apis/uiplugin/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

186 changes: 183 additions & 3 deletions pkg/controllers/uiplugin/components.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package uiplugin

import (
"bytes"
"embed"
"fmt"
"hash/fnv"
"io"
"sort"
"text/template"

osv1alpha1 "github.com/openshift/api/console/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
Expand All @@ -18,9 +22,13 @@ import (
)

const (
port = 9443
serviceAccountSuffix = "-sa"
servingCertVolumeName = "serving-cert"
port = 9443
serviceAccountSuffix = "-sa"
servingCertVolumeName = "serving-cert"
Korrel8rConfigFileName = "korrel8r.yaml"
Korrel8rConfigMountDir = "/config/"
OpenshiftLoggingNs = "openshift-logging"
OpenshiftNetobservNs = "netobserv"

annotationPrefix = "observability.openshift.io/ui-plugin-"
)
Expand All @@ -31,6 +39,9 @@ var (
}

hashSeparator = []byte("\n")

//go:embed config/korrel8r.yaml
korrel8rConfigYAMLTmplFile embed.FS
)

func pluginComponentReconcilers(plugin *uiv1alpha1.UIPlugin, pluginInfo UIPluginInfo) []reconciler.Reconciler {
Expand Down Expand Up @@ -67,6 +78,16 @@ func pluginComponentReconcilers(plugin *uiv1alpha1.UIPlugin, pluginInfo UIPlugin
}
}

if pluginInfo.Korrel8rImage != "" {
kname := "korrel8r"
components = append(components, reconciler.NewUpdater(newKorrel8rService(kname, namespace), plugin))
korrel8rCm, err := newKorrel8rConfigMap(kname, namespace, pluginInfo)
if err == nil && korrel8rCm != nil {
components = append(components, reconciler.NewUpdater(korrel8rCm, plugin))
components = append(components, reconciler.NewUpdater(newKorrel8rDeployment(kname, namespace, pluginInfo), plugin))
}
}

return components
}

Expand Down Expand Up @@ -295,6 +316,165 @@ func newService(info UIPluginInfo, namespace string) *corev1.Service {
}
}

func newKorrel8rDeployment(name string, namespace string, info UIPluginInfo) *appsv1.Deployment {
volumes := []corev1.Volume{
{
Name: servingCertVolumeName,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: name,
DefaultMode: ptr.To(int32(420)),
},
},
},
}
volumeMounts := []corev1.VolumeMount{
{
Name: servingCertVolumeName,
ReadOnly: true,
MountPath: "/secrets/",
},
}

volumes = append(volumes, corev1.Volume{
Name: "korrel8r-config",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: name,
},
},
},
})
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: "korrel8r-config",
ReadOnly: true,
MountPath: Korrel8rConfigMountDir,
})

deploy := &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
APIVersion: appsv1.SchemeGroupVersion.String(),
Kind: "Deployment",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: componentLabels(name),
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{
MatchLabels: componentLabels(name),
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: componentLabels(name),
},
Spec: corev1.PodSpec{
ServiceAccountName: info.Name + serviceAccountSuffix,
Containers: []corev1.Container{
{
Name: name,
Image: info.Korrel8rImage,
Command: []string{"korrel8r", "web", "--https=:8443", "--cert=/secrets/tls.crt", "--key=/secrets/tls.key", "--config=/config/korrel8r.yaml"},
Ports: []corev1.ContainerPort{
{
ContainerPort: 8443,
Protocol: corev1.ProtocolTCP,
},
},
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: ptr.To(true),
AllowPrivilegeEscalation: ptr.To(false),
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{
"ALL",
},
},
SeccompProfile: &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
},
},
VolumeMounts: volumeMounts,
},
},
Volumes: volumes,
},
},
},
}
return deploy
}

func newKorrel8rService(name string, namespace string) *corev1.Service {
annotations := map[string]string{
"service.beta.openshift.io/serving-cert-secret-name": name,
}

return &corev1.Service{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1.SchemeGroupVersion.String(),
Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: componentLabels(name),
Annotations: annotations,
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Port: port,
Name: "web",
Protocol: corev1.ProtocolTCP,
TargetPort: intstr.FromInt32(port),
},
},
Selector: componentLabels(name),
Type: corev1.ServiceTypeClusterIP,
},
}
}

func newKorrel8rConfigMap(name string, namespace string, info UIPluginInfo) (*corev1.ConfigMap, error) {

korrel8rData := map[string]string{"Metric": "thanos-querier", "MetricAlert": "alertmanager-main", "Log": "logging-loki-gateway-http", "Netflow": "loki-gateway-http", "MonitoringNs": "openshift-monitoring", "LoggingNs": OpenshiftLoggingNs, "NetobservNs": OpenshiftNetobservNs}

if info.LokiServiceNames[OpenshiftLoggingNs] != "" {
korrel8rData["LoggingNs"] = info.LokiServiceNames[OpenshiftLoggingNs]
}
if info.LokiServiceNames[OpenshiftNetobservNs] != "" {
korrel8rData["NetobservNs"] = info.LokiServiceNames[OpenshiftNetobservNs]
}

var korrel8rConfigYAMLTmpl = template.Must(template.ParseFS(korrel8rConfigYAMLTmplFile, "config/korrel8r.yaml"))
w := bytes.NewBuffer(nil)
err := korrel8rConfigYAMLTmpl.Execute(w, korrel8rData)
if err != nil {
return nil, err
}

cfg, _ := io.ReadAll(w)

return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
APIVersion: corev1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: componentLabels(name),
},
Data: map[string]string{
Korrel8rConfigFileName: string(cfg),
},
}, nil
}

func componentLabels(pluginName string) map[string]string {
return map[string]string{
"app.kubernetes.io/instance": pluginName,
Expand Down
Loading
Loading