diff --git a/Makefile b/Makefile index 1d3015ea4..ccfe61452 100644 --- a/Makefile +++ b/Makefile @@ -160,6 +160,16 @@ BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) endif BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) +# Adjust sed command to include '' if on MacOS (Darwin) +ifeq ($(shell uname), Darwin) + BUNDLE_SED_COMMAND = sed -e 's||$(OPERATOR_IMG)|g' \ + -i '' bundle/manifests/observability-operator.clusterserviceversion.yaml +else + BUNDLE_SED_COMMAND = sed -e 's||$(OPERATOR_IMG)|g' \ + -i bundle/manifests/observability-operator.clusterserviceversion.yaml +endif + + .PHONY: bundle bundle: $(KUSTOMIZE) $(OPERATOR_SDK) generate @@ -170,8 +180,7 @@ bundle: $(KUSTOMIZE) $(OPERATOR_SDK) generate --kustomize-dir=deploy/olm \ --package=observability-operator \ $(BUNDLE_METADATA_OPTS) - sed -e 's||$(OPERATOR_IMG)|g' \ - -i bundle/manifests/observability-operator.clusterserviceversion.yaml + $(BUNDLE_SED_COMMAND) $(OPERATOR_SDK) bundle validate ./bundle \ --select-optional name=operatorhub \ --optional-values=k8s-version=1.21 \ diff --git a/bundle/manifests/observability-operator.clusterserviceversion.yaml b/bundle/manifests/observability-operator.clusterserviceversion.yaml index ccdd6420f..f1b6cde8b 100644 --- a/bundle/manifests/observability-operator.clusterserviceversion.yaml +++ b/bundle/manifests/observability-operator.clusterserviceversion.yaml @@ -42,7 +42,7 @@ metadata: categories: Monitoring certified: "false" containerImage: observability-operator:1.0.0 - createdAt: "2024-12-11T10:22:00Z" + createdAt: "2025-01-14T21:22:22Z" description: A Go based Kubernetes operator to setup and manage highly available Monitoring Stack using Prometheus, Alertmanager and Thanos Querier. operatorframework.io/cluster-monitoring: "true" diff --git a/bundle/manifests/observability.openshift.io_uiplugins.yaml b/bundle/manifests/observability.openshift.io_uiplugins.yaml index c302643a4..1ece566c0 100644 --- a/bundle/manifests/observability.openshift.io_uiplugins.yaml +++ b/bundle/manifests/observability.openshift.io_uiplugins.yaml @@ -156,6 +156,23 @@ spec: - url type: object x-kubernetes-map-type: atomic + perses: + description: Perses points to the perses instance service of which + it should create a proxy to. + properties: + name: + description: Name of the Perses Service to proxy to. + minLength: 1 + type: string + namespace: + description: Namespace of the Perses Service to proxy to. + minLength: 1 + type: string + required: + - name + - namespace + type: object + x-kubernetes-map-type: atomic thanosQuerier: description: ThanosQuerier points to the thanos-querier service of which it should create a proxy to. @@ -168,9 +185,6 @@ spec: - url type: object x-kubernetes-map-type: atomic - required: - - alertmanager - - thanosQuerier type: object troubleshootingPanel: description: TroubleshootingPanel contains configuration for the troubleshooting diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 1fb59facf..fbff588e5 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -43,7 +43,7 @@ var defaultImages = map[string]string{ "ui-troubleshooting-panel": "quay.io/openshift-observability-ui/troubleshooting-panel-console-plugin:v0.3.0", "ui-distributed-tracing": "quay.io/openshift-observability-ui/distributed-tracing-console-plugin:v0.3.0", "ui-logging": "quay.io/openshift-observability-ui/logging-view-plugin:v6.0.0", - "ui-monitoring": "quay.io/openshift-observability-ui/monitoring-console-plugin:latest", + "ui-monitoring": "quay.io/rh-ee-pyurkovi/monitoring-plugin:perses", // JZ NEED THIS FOR TEST WITH 'PERSES-DASHBOARD' FEATURE FLAG ON MONTIORING-CONSOLE-PLUGIN "korrel8r": "quay.io/korrel8r/korrel8r:0.7.4", } @@ -91,7 +91,7 @@ func main() { flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&healthProbeAddr, "health-probe-bind-address", ":8081", "The address the health probe endpoint binds to.") flag.Var(images, "images", fmt.Sprintf("Full images refs to use for containers managed by the operator. E.g thanos=quay.io/thanos/thanos:v0.33.0. Images used are %v", imagesUsed())) - flag.BoolVar(&openShiftEnabled, "openshift.enabled", false, "Enable OpenShift specific features such as Console Plugins.") + flag.BoolVar(&openShiftEnabled, "openshift.enabled", true, "Enable OpenShift specific features such as Console Plugins.") opts := zap.Options{ Development: true, diff --git a/deploy/crds/common/observability.openshift.io_uiplugins.yaml b/deploy/crds/common/observability.openshift.io_uiplugins.yaml index 238a79a94..18e53717a 100644 --- a/deploy/crds/common/observability.openshift.io_uiplugins.yaml +++ b/deploy/crds/common/observability.openshift.io_uiplugins.yaml @@ -156,6 +156,23 @@ spec: - url type: object x-kubernetes-map-type: atomic + perses: + description: Perses points to the perses instance service of which + it should create a proxy to. + properties: + name: + description: Name of the Perses Service to proxy to. + minLength: 1 + type: string + namespace: + description: Namespace of the Perses Service to proxy to. + minLength: 1 + type: string + required: + - name + - namespace + type: object + x-kubernetes-map-type: atomic thanosQuerier: description: ThanosQuerier points to the thanos-querier service of which it should create a proxy to. @@ -168,9 +185,6 @@ spec: - url type: object x-kubernetes-map-type: atomic - required: - - alertmanager - - thanosQuerier type: object troubleshootingPanel: description: TroubleshootingPanel contains configuration for the troubleshooting diff --git a/docs/api.md b/docs/api.md index 790ff4662..79fa32c61 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4173,14 +4173,21 @@ Monitoring contains configuration for the monitoring console plugin. Alertmanager points to the alertmanager instance of which it should create a proxy to.
- true + false + + perses + object + + Perses points to the perses instance service of which it should create a proxy to.
+ + false thanosQuerier object ThanosQuerier points to the thanos-querier service of which it should create a proxy to.
- true + false @@ -4212,6 +4219,40 @@ Alertmanager points to the alertmanager instance of which it should create a pro +### UIPlugin.spec.monitoring.perses +[↩ Parent](#uipluginspecmonitoring) + + + +Perses points to the perses instance service of which it should create a proxy to. + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
namestring + Name of the Perses Service to proxy to.
+
true
namespacestring + Namespace of the Perses Service to proxy to.
+
true
+ + ### UIPlugin.spec.monitoring.thanosQuerier [↩ Parent](#uipluginspecmonitoring) diff --git a/docs/user-guides/observability-ui-plugins.md b/docs/user-guides/observability-ui-plugins.md index 56e22d77e..85ab66506 100644 --- a/docs/user-guides/observability-ui-plugins.md +++ b/docs/user-guides/observability-ui-plugins.md @@ -136,17 +136,22 @@ spec: ### Monitoring -The plugin adds monitoring related UI features to the OpenShift web console, mostly related to the ACM perspective. A number of new pages and features are enabled through this plugin. Including, but not limited to: +The plugin adds monitoring related UI features to the OpenShift web console, related to the Advance Cluster Management (ACM) perspective and [Perses](https://github.com/perses/perses). A number of new pages and features are enabled through this plugin. Including, but not limited to: - `ACM > Observe > Alerting` - `ACM > Observe > Alerting > Silences` - `ACM > Observe > Alerting > Alert rules` +- `Observe > Dashboards > Perses Dashboards` -This plugin is only able to be deployed by COO with the `acm-alerting` configuration enabled. Other pages which are typically distributed with the monitoring-plugin, such as `Admin > Observe > Dashboards`, are only available in the monitoring-plugin when deployed through [CMO](https://github.com/openshift/cluster-monitoring-operator). +To deploy ACM related features the `acm-alerting` configuration must be enabled. In the UIPlugin Custom Resource (CR) you must pass the Alertmanager and ThanosQuerier Service endpoint (e.g. `https://alertmanager.open-cluster-management-observability.svc:9095` and `https://rbac-query-proxy.open-cluster-management-observability.svc:8443`). See the example in the next section `Plugin Creation`. -#### Plugin Creation +Other pages which are typically distributed with the monitoring-plugin, such as `Admin > Observe > Dashboards`, are only available in the monitoring-plugin when deployed through [CMO](https://github.com/openshift/cluster-monitoring-operator). + +To deploy the Perses dashboard feature the `perses-dashboards` configuration must be enabled. In the UIPlugin CR you can optionally pass the service name and namespace of your Perses instance. Otherwise it will default to the service name `perses-api-http` and namespace `perses-operator`. See the example in the next section `Plugin Creation`. +#### Plugin Creation To enable to monitoring console plugin, create a `UIPlugin` CR. The following example shows how to create a CR to enable the monitoring console plugin: + ```yaml apiVersion: observability.openshift.io/v1alpha1 kind: UIPlugin @@ -159,6 +164,9 @@ spec: url: 'https://alertmanager.open-cluster-management-observability.svc:9095' thanosQuerier: url: 'https://rbac-query-proxy.open-cluster-management-observability.svc:8443' + perses: + name: 'perses-api-http' + namespace: 'perses-operator' ``` #### Feature List @@ -166,9 +174,11 @@ spec: | __Feature__ | __Description__ | | -------------- | --------------------------------------------------------------------------------------------------------------- | | `acm-alerting` | Adds alerting UI to multi-cluster view. Configures proxies to connect with any alertmanager and thanos-querier. | +| `perses-dashboards` | Adds perses UI to Observe > Dashboards view. Configures proxies to connect with a Perses instance. | #### Feature Matrix | __COO Version__ | __OCP Versions__ | __Features__ | | --------------- | ------------------- | -------------- | | 1.0.0+ | 4.14+ | `acm-alerting` | +| 1.1.0+ | 4.19+ | `acm-alerting, perses-dashboards` | \ No newline at end of file diff --git a/pkg/apis/uiplugin/v1alpha1/types.go b/pkg/apis/uiplugin/v1alpha1/types.go index e5c408de3..e3ab02720 100644 --- a/pkg/apis/uiplugin/v1alpha1/types.go +++ b/pkg/apis/uiplugin/v1alpha1/types.go @@ -139,13 +139,18 @@ type LokiStackReference struct { type MonitoringConfig struct { // Alertmanager points to the alertmanager instance of which it should create a proxy to. // - // +kubebuilder:validation:Required + // +kubebuilder:validation:Optional Alertmanager AlertmanagerReference `json:"alertmanager"` // ThanosQuerier points to the thanos-querier service of which it should create a proxy to. // - // +kubebuilder:validation:Required + // +kubebuilder:validation:Optional ThanosQuerier ThanosQuerierReference `json:"thanosQuerier"` + + // Perses points to the perses instance service of which it should create a proxy to. + // + // +kubebuilder:validation:Optional + Perses PersesReference `json:"perses"` } // Alertmanager is used to configure a reference to a alertmanage that should be used @@ -157,7 +162,7 @@ type AlertmanagerReference struct { // // +kubebuilder:validation:Required // +kubebuilder:validation:MinLength:=1 - Url string `json:"url"` + Url string `json:"url,omitempty"` } // ThanosQuerier is used to configure a reference to a thanos-querier service that should be used @@ -169,7 +174,24 @@ type ThanosQuerierReference struct { // // +kubebuilder:validation:Required // +kubebuilder:validation:MinLength:=1 - Url string `json:"url"` + Url string `json:"url,omitempty"` +} + +// Perses is used to configure a reference to a perses service that should be used +// by the monitoring console plugin. +// +// +structType=atomic +type PersesReference struct { + // Name of the Perses Service to proxy to. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength:=1 + Name string `json:"name,omitempty"` + // Namespace of the Perses Service to proxy to. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength:=1 + Namespace string `json:"namespace,omitempty"` } // UIPluginSpec is the specification for desired state of UIPlugin. diff --git a/pkg/apis/uiplugin/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/uiplugin/v1alpha1/zz_generated.deepcopy.go index 2e35968fa..897bbc0da 100644 --- a/pkg/apis/uiplugin/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/uiplugin/v1alpha1/zz_generated.deepcopy.go @@ -136,6 +136,7 @@ func (in *MonitoringConfig) DeepCopyInto(out *MonitoringConfig) { *out = *in out.Alertmanager = in.Alertmanager out.ThanosQuerier = in.ThanosQuerier + out.Perses = in.Perses } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonitoringConfig. @@ -148,6 +149,21 @@ func (in *MonitoringConfig) DeepCopy() *MonitoringConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersesReference) DeepCopyInto(out *PersesReference) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersesReference. +func (in *PersesReference) DeepCopy() *PersesReference { + if in == nil { + return nil + } + out := new(PersesReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ThanosQuerierReference) DeepCopyInto(out *ThanosQuerierReference) { *out = *in diff --git a/pkg/controllers/uiplugin/compatibility_matrix.go b/pkg/controllers/uiplugin/compatibility_matrix.go index 4b8bc2dce..bd5acd617 100644 --- a/pkg/controllers/uiplugin/compatibility_matrix.go +++ b/pkg/controllers/uiplugin/compatibility_matrix.go @@ -120,6 +120,31 @@ var compatibilityMatrix = []CompatibilityEntry{ "dev-alerts", }, }, + { + PluginType: uiv1alpha1.TypeMonitoring, + MinClusterVersion: "v4.19", + MaxClusterVersion: "", + ImageKey: "ui-monitoring", + MinAcmVersion: "v2.11", + MaxAcmVersion: "", + SupportLevel: DevPreview, + Features: []string{ + "perses-dashboards", + "acm-alerting", + }, + }, + { + PluginType: uiv1alpha1.TypeMonitoring, + MinClusterVersion: "v4.19", + MaxClusterVersion: "", + ImageKey: "ui-monitoring", + MinAcmVersion: "", + MaxAcmVersion: "", + SupportLevel: DevPreview, + Features: []string{ + "perses-dashboards", + }, + }, { PluginType: uiv1alpha1.TypeMonitoring, MinClusterVersion: "v4.14", @@ -135,6 +160,7 @@ var compatibilityMatrix = []CompatibilityEntry{ } func lookupImageAndFeatures(pluginType uiv1alpha1.UIPluginType, clusterVersion string, acmVersion string) (CompatibilityEntry, error) { + if !strings.HasPrefix(clusterVersion, "v") { clusterVersion = "v" + clusterVersion } diff --git a/pkg/controllers/uiplugin/compatibility_matrix_test.go b/pkg/controllers/uiplugin/compatibility_matrix_test.go index 4952faceb..c909cf656 100644 --- a/pkg/controllers/uiplugin/compatibility_matrix_test.go +++ b/pkg/controllers/uiplugin/compatibility_matrix_test.go @@ -2,6 +2,8 @@ package uiplugin import ( "fmt" + // "log" + "slices" "testing" "golang.org/x/mod/semver" @@ -37,6 +39,11 @@ func TestCompatibilityMatrixMaxVersions(t *testing.T) { continue } + // exception for montioring-plugin usage of perses-dashboards + if v.PluginType == "Monitoring" && slices.Contains(v.Features, "perses-dashboards") { + continue + } + _, found := cm[v.PluginType] assert.Assert(t, !found, string(v.PluginType)) cm[v.PluginType] = struct{}{} @@ -242,6 +249,46 @@ func TestLookupImageAndFeatures(t *testing.T) { expectedFeatures: []string{"acm-alerting"}, expectedErr: nil, }, + { + pluginType: uiv1alpha1.TypeMonitoring, + clusterVersion: "v4.19", + acmVersion: "v2.11.3", + expectedKey: "ui-monitoring", + expectedFeatures: []string{"perses-dashboards", "acm-alerting"}, + expectedErr: nil, + }, + { + pluginType: uiv1alpha1.TypeMonitoring, + clusterVersion: "v4.19.0-0.nightly-2024-06-06-064349", + acmVersion: "v2.11.3", + expectedKey: "ui-monitoring", + expectedFeatures: []string{"perses-dashboards", "acm-alerting"}, + expectedErr: nil, + }, + { + pluginType: uiv1alpha1.TypeMonitoring, + clusterVersion: "v4.19", + acmVersion: "", + expectedKey: "ui-monitoring", + expectedFeatures: []string{"perses-dashboards"}, + expectedErr: nil, + }, + { + pluginType: uiv1alpha1.TypeMonitoring, + clusterVersion: "v4.19.0-0.nightly-2024-06-06-064349", + acmVersion: "", + expectedKey: "ui-monitoring", + expectedFeatures: []string{"perses-dashboards"}, + expectedErr: nil, + }, + { + pluginType: uiv1alpha1.TypeMonitoring, + clusterVersion: "v4.19", + acmVersion: "v2.10", + expectedKey: "ui-monitoring", + expectedFeatures: []string{"perses-dashboards"}, + expectedErr: nil, + }, } { t.Run(fmt.Sprintf("%s/%s", tc.pluginType, tc.clusterVersion), func(t *testing.T) { info, err := lookupImageAndFeatures(tc.pluginType, tc.clusterVersion, tc.acmVersion) diff --git a/pkg/controllers/uiplugin/controller.go b/pkg/controllers/uiplugin/controller.go index 714e43b68..308621c1b 100644 --- a/pkg/controllers/uiplugin/controller.go +++ b/pkg/controllers/uiplugin/controller.go @@ -185,6 +185,8 @@ func (rm resourceManager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl return ctrl.Result{}, nil } + logger.Info("JZ plugin: ", plugin) + // Check if the plugin is being deleted if !plugin.ObjectMeta.DeletionTimestamp.IsZero() { logger.V(6).Info("deregistering plugin from the console") @@ -227,11 +229,19 @@ func (rm resourceManager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl } } + // JZ TESTING TO BE REMOVED + logger.Info("JZ plugin.Spec.Type", plugin.Spec.Type) + logger.Info("JZ rm.clusterVersion", rm.clusterVersion) + logger.Info("JZ acmVersion", acmVersion) + compatibilityInfo, err := lookupImageAndFeatures(plugin.Spec.Type, rm.clusterVersion, acmVersion) if err != nil { + logger.Info("JZ ERROR compatibilityInfo: \n", compatibilityInfo) return ctrl.Result{}, err } + logger.Info("JZ compatibilityInfo: \n", compatibilityInfo) + if plugin.Annotations == nil { plugin.Annotations = map[string]string{} plugin.Annotations["observability.openshift.io/api-support"] = string(compatibilityInfo.SupportLevel) diff --git a/pkg/controllers/uiplugin/monitoring.go b/pkg/controllers/uiplugin/monitoring.go index 29e9e712e..d20af486a 100644 --- a/pkg/controllers/uiplugin/monitoring.go +++ b/pkg/controllers/uiplugin/monitoring.go @@ -2,6 +2,7 @@ package uiplugin import ( "fmt" + "slices" "strings" osv1 "github.com/openshift/api/console/v1" @@ -15,6 +16,12 @@ import ( func createMonitoringPluginInfo(plugin *uiv1alpha1.UIPlugin, namespace, name, image string, features []string) (*UIPluginInfo, error) { config := plugin.Spec.Monitoring + persesDashboardsFeatureEnabled := slices.Contains(features, "perses-dashboards") + + // Default service name and namespace for Perses + var persesName = "perses-api-http" + var persesNamespace = "perses-operator" + if config == nil { return nil, fmt.Errorf("monitoring configuration can not be empty for plugin type %s", plugin.Spec.Type) } @@ -25,6 +32,10 @@ func createMonitoringPluginInfo(plugin *uiv1alpha1.UIPlugin, namespace, name, im if config.ThanosQuerier.Url == "" { return nil, fmt.Errorf("ThanosQuerier location can not be empty for plugin type %s", plugin.Spec.Type) } + if persesDashboardsFeatureEnabled && config.Perses.Name != "" && config.Perses.Namespace != "" { + persesName = config.Perses.Name + persesNamespace = config.Perses.Namespace + } pluginInfo := &UIPluginInfo{ Image: image, @@ -111,6 +122,31 @@ func createMonitoringPluginInfo(plugin *uiv1alpha1.UIPlugin, namespace, name, im }, } + if persesDashboardsFeatureEnabled { + pluginInfo.Proxies = append(pluginInfo.Proxies, osv1.ConsolePluginProxy{ + Alias: "perses", + Authorization: "UserToken", + Endpoint: osv1.ConsolePluginProxyEndpoint{ + Type: osv1.ProxyTypeService, + Service: &osv1.ConsolePluginProxyServiceConfig{ + Name: persesName, + Namespace: persesNamespace, + Port: 8080, + }, + }, + }) + pluginInfo.LegacyProxies = append(pluginInfo.LegacyProxies, osv1alpha1.ConsolePluginProxy{ + Type: "Service", + Alias: "perses", + Authorize: true, + Service: osv1alpha1.ConsolePluginProxyServiceConfig{ + Name: persesName, + Namespace: persesNamespace, + Port: 8080, + }, + }) + } + return pluginInfo, nil } @@ -150,6 +186,12 @@ func newMonitoringService(name string, namespace string) *corev1.Service { Protocol: corev1.ProtocolTCP, TargetPort: intstr.FromInt32(9445), }, + { + Port: 8080, + Name: "perses", + Protocol: corev1.ProtocolTCP, + TargetPort: intstr.FromInt32(8080), + }, }, Selector: componentLabels(name), Type: corev1.ServiceTypeClusterIP, diff --git a/pkg/controllers/uiplugin/monitoring_test.go b/pkg/controllers/uiplugin/monitoring_test.go new file mode 100644 index 000000000..c05cb9319 --- /dev/null +++ b/pkg/controllers/uiplugin/monitoring_test.go @@ -0,0 +1,65 @@ +package uiplugin + +import ( + "testing" + + "gotest.tools/v3/assert" + + uiv1alpha1 "github.com/rhobs/observability-operator/pkg/apis/uiplugin/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var plugin = &uiv1alpha1.UIPlugin{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "observability.openshift.io/v1alpha1", + Kind: "UIPlugin", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "monitoring-plugin", + }, + Spec: uiv1alpha1.UIPluginSpec{ + Type: "monitoring", + + Monitoring: &uiv1alpha1.MonitoringConfig{ + Alertmanager: uiv1alpha1.AlertmanagerReference{ + Url: "https://alertmanager.open-cluster-management-observability.svc:9095", + }, + ThanosQuerier: uiv1alpha1.ThanosQuerierReference{ + Url: "https://rbac-query-proxy.open-cluster-management-observability.svc:8443", + }, + Perses: uiv1alpha1.PersesReference{ + Name: "perses-api-http", + Namespace: "perses-operator", + }, + }, + }, +} +var namespace = "openshift-operators" +var name = "monitoring" +var image = "quay.io/monitoring-foo-test:123" +var features = []string{"perses-dashboards", "acm-alerting"} + +func TestCreateMonitoringPluginInfo(t *testing.T) { + t.Run("Test createMontiroingPluginInfo", func(t *testing.T) { + pluginInfo, _ := createMonitoringPluginInfo(plugin, namespace, name, image, features) + + containsPersesProxy := func() bool { + for _, proxy := range pluginInfo.Proxies { + if proxy.Alias == "perses" { + return true + } + } + return false + } + + assert.Assert(t, containsPersesProxy() == true) + + // JZ TO REMOVE -- for testing only to output pluginInfo object + // prettyJSON, err := json.MarshalIndent(pluginInfo, "", " ") + // if err != nil { + // log.Fatalf("Error pretty printing JSON: %v", err) + // } + // fmt.Println(string(prettyJSON)) + // assert.Equal(t, pluginInfo, true) + }) +}