diff --git a/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go b/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go index de03d3b355..70b4d30ab7 100644 --- a/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go +++ b/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go @@ -13,6 +13,9 @@ import ( // MultiClusterObservabilitySpec defines the desired state of MultiClusterObservability. type MultiClusterObservabilitySpec struct { + // Platform and UserWorkload Observability Capabilities + // +optional + Capabilities *CapabilitiesSpec `json:"capabilities,omitempty"` // Advanced configurations for observability // +optional AdvancedConfig *AdvancedConfig `json:"advanced,omitempty"` @@ -41,6 +44,59 @@ type MultiClusterObservabilitySpec struct { ObservabilityAddonSpec *observabilityshared.ObservabilityAddonSpec `json:"observabilityAddonSpec"` } +type LogsCollectionSpec struct { + // +optional + Enabled bool `json:"enabled,omitempty"` +} + +type PlatformLogsSpec struct { + // +optional + Collection *LogsCollectionSpec `json:"collection,omitempty"` +} + +type PlatformCapabilitiesSpec struct { + // +optional + Logs LogsCollectionSpec `json:"logs,omitempty"` +} + +type ClusterLogForwarderSpec struct { + // +optional + Enabled bool `json:"enabled,omitempty"` +} + +type UserWorkloadLogsSpec struct { + ClusterLogForwarder ClusterLogForwarderSpec `json:"clusterLogForwarder,omitempty"` +} + +type OpenTelemetryCollectorSpec struct { + // +optional + Enabled bool `json:"enabled,omitempty"` +} + +type InstrumentationSpec struct { + // +optional + Enabled bool `json:"enabled,omitempty"` +} + +type UserWorkloadTracesSpec struct { + // +optional + OpenTelemetryCollector OpenTelemetryCollectorSpec `json:"openTelemetryCollector,omitempty"` + // +optional + Instrumentation InstrumentationSpec `json:"instrumentation,omitempty"` +} + +type UserWorkloadCapabilitiesSpec struct { + Logs UserWorkloadLogsSpec `json:"logs,omitempty"` + Traces UserWorkloadTracesSpec `json:"traces,omitempty"` +} + +type CapabilitiesSpec struct { + // +optional + Platform *PlatformCapabilitiesSpec `json:"platform,omitempty"` + // +optional + UserWorkloads *UserWorkloadCapabilitiesSpec `json:"userWorkloads,omitempty"` +} + type AdvancedConfig struct { // CustomObservabilityHubURL overrides the endpoint used by the metrics-collector to send // metrics to the hub server. @@ -91,6 +147,8 @@ type AdvancedConfig struct { // spec for thanos-store-shard // +optional Store *StoreSpec `json:"store,omitempty"` + // spec for multicluster-obervability-addon + MultiClusterObservabilityAddon *CommonSpec `json:"multiClusterObservabilityAddon,omitempty"` } type CommonSpec struct { diff --git a/operators/multiclusterobservability/bundle/manifests/observability.open-cluster-management.io_multiclusterobservabilities.yaml b/operators/multiclusterobservability/bundle/manifests/observability.open-cluster-management.io_multiclusterobservabilities.yaml index 7c449d53f7..f1d2bd4979 100644 --- a/operators/multiclusterobservability/bundle/manifests/observability.open-cluster-management.io_multiclusterobservabilities.yaml +++ b/operators/multiclusterobservability/bundle/manifests/observability.open-cluster-management.io_multiclusterobservabilities.yaml @@ -1203,6 +1203,51 @@ spec: type: object type: object type: object + multiClusterObservabilityAddon: + description: spec for multicluster-obervability-addon + properties: + replicas: + description: Replicas for this component. + format: int32 + type: integer + resources: + description: Compute Resources required by this component. + properties: + claims: + description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + type: object observatoriumAPI: description: Spec of observatorium api properties: @@ -5654,6 +5699,42 @@ spec: type: object type: object type: object + capabilities: + description: Platform and UserWorkload Observability Capabilities + properties: + platform: + properties: + logs: + properties: + enabled: + type: boolean + type: object + type: object + userWorkloads: + properties: + logs: + properties: + clusterLogForwarder: + properties: + enabled: + type: boolean + type: object + type: object + traces: + properties: + instrumentation: + properties: + enabled: + type: boolean + type: object + openTelemetryCollector: + properties: + enabled: + type: boolean + type: object + type: object + type: object + type: object enableDownsampling: default: true description: Enable or disable the downsample. diff --git a/operators/multiclusterobservability/config/crd/bases/observability.open-cluster-management.io_multiclusterobservabilities.yaml b/operators/multiclusterobservability/config/crd/bases/observability.open-cluster-management.io_multiclusterobservabilities.yaml index 180cce9730..7b68cfe6af 100644 --- a/operators/multiclusterobservability/config/crd/bases/observability.open-cluster-management.io_multiclusterobservabilities.yaml +++ b/operators/multiclusterobservability/config/crd/bases/observability.open-cluster-management.io_multiclusterobservabilities.yaml @@ -1833,6 +1833,63 @@ spec: type: object type: object type: object + multiClusterObservabilityAddon: + description: spec for multicluster-obervability-addon + properties: + replicas: + description: Replicas for this component. + format: int32 + type: integer + resources: + description: Compute Resources required by this component. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. \n This field + is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + type: object observatoriumAPI: description: Spec of observatorium api properties: @@ -9018,6 +9075,42 @@ spec: type: object type: object type: object + capabilities: + description: Platform and UserWorkload Observability Capabilities + properties: + platform: + properties: + logs: + properties: + enabled: + type: boolean + type: object + type: object + userWorkloads: + properties: + logs: + properties: + clusterLogForwarder: + properties: + enabled: + type: boolean + type: object + type: object + traces: + properties: + instrumentation: + properties: + enabled: + type: boolean + type: object + openTelemetryCollector: + properties: + enabled: + type: boolean + type: object + type: object + type: object + type: object enableDownsampling: default: true description: Enable or disable the downsample. diff --git a/operators/multiclusterobservability/pkg/config/config.go b/operators/multiclusterobservability/pkg/config/config.go index 0ce7a5b364..b0106b5473 100644 --- a/operators/multiclusterobservability/pkg/config/config.go +++ b/operators/multiclusterobservability/pkg/config/config.go @@ -158,6 +158,11 @@ const ( EndpointControllerImgName = "endpoint-monitoring-operator" EndpointControllerKey = "endpoint_monitoring_operator" + MultiClusterObservabilityAddonImgRepo = "quay.io/rhobs" + MultiClusterObservabilityAddonImgName = "multicluster-observability-addon" + MultiClusterObservabilityAddonImgTagSuffix = "0.0.1" + MultiClusterObservabilityAddonImgKey = "multicluster_observability_addon" + RBACQueryProxyImgName = "rbac-query-proxy" RBACQueryProxyKey = "rbac_query_proxy" @@ -211,23 +216,29 @@ const ( MetricsCollectorCPULimits = "" MetricsCollectorMemoryLimits = "" - ObservatoriumAPI = "observatorium-api" - ThanosCompact = "thanos-compact" - ThanosQuery = "thanos-query" - ThanosQueryFrontend = "thanos-query-frontend" - ThanosQueryFrontendMemcached = "thanos-query-frontend-memcached" - ThanosRule = "thanos-rule" - ThanosReceive = "thanos-receive-default" - ThanosStoreMemcached = "thanos-store-memcached" - ThanosStoreShard = "thanos-store-shard" - MemcachedExporter = "memcached-exporter" - Grafana = "grafana" - RBACQueryProxy = "rbac-query-proxy" - Alertmanager = "alertmanager" - ThanosReceiveController = "thanos-receive-controller" - ObservatoriumOperator = "observatorium-operator" - MetricsCollector = "metrics-collector" - Observatorium = "observatorium" + MCOACPURequests = "100m" + MCOACPULimits = "200m" + MCOAMemoryRequests = "256Mi" + MCOAMemoryLimits = "512Mi" + + ObservatoriumAPI = "observatorium-api" + ThanosCompact = "thanos-compact" + ThanosQuery = "thanos-query" + ThanosQueryFrontend = "thanos-query-frontend" + ThanosQueryFrontendMemcached = "thanos-query-frontend-memcached" + ThanosRule = "thanos-rule" + ThanosReceive = "thanos-receive-default" + ThanosStoreMemcached = "thanos-store-memcached" + ThanosStoreShard = "thanos-store-shard" + MemcachedExporter = "memcached-exporter" + Grafana = "grafana" + RBACQueryProxy = "rbac-query-proxy" + Alertmanager = "alertmanager" + ThanosReceiveController = "thanos-receive-controller" + ObservatoriumOperator = "observatorium-operator" + MetricsCollector = "metrics-collector" + Observatorium = "observatorium" + MultiClusterObservabilityAddon = "multicluster-observability-addon" RetentionResolutionRaw = "365d" RetentionResolution5m = "365d" @@ -828,7 +839,8 @@ func GetImagePullSecret(mco observabilityv1beta2.MultiClusterObservabilitySpec) } func getDefaultResource(resourceType string, resource corev1.ResourceName, - component string) string { + component string, +) string { // No provide the default limits if resourceType == ResourceLimits && component != Grafana { return "" @@ -934,12 +946,30 @@ func getDefaultResource(resourceType string, resource corev1.ResourceName, return GrafanaMemoryLimits } } + case MultiClusterObservabilityAddon: + if resourceType == ResourceRequests { + if resource == corev1.ResourceCPU { + return MCOACPURequests + } + if resource == corev1.ResourceMemory { + return MCOAMemoryRequests + } + } else if resourceType == ResourceLimits { + if resource == corev1.ResourceCPU { + return MCOACPULimits + } + if resource == corev1.ResourceMemory { + return MCOACPULimits + } + } + } return "" } func getResource(resourceType string, resource corev1.ResourceName, - component string, advanced *observabilityv1beta2.AdvancedConfig) string { + component string, advanced *observabilityv1beta2.AdvancedConfig, +) string { if advanced == nil { return getDefaultResource(resourceType, resource, component) } @@ -993,6 +1023,10 @@ func getResource(resourceType string, resource corev1.ResourceName, if advanced.Alertmanager != nil { resourcesReq = advanced.Alertmanager.Resources } + case MultiClusterObservabilityAddon: + if advanced.MultiClusterObservabilityAddon != nil { + resourcesReq = advanced.MultiClusterObservabilityAddon.Resources + } } if resourcesReq != nil { @@ -1029,7 +1063,6 @@ func getResource(resourceType string, resource corev1.ResourceName, } func GetResources(component string, advanced *observabilityv1beta2.AdvancedConfig) corev1.ResourceRequirements { - cpuRequests := getResource(ResourceRequests, corev1.ResourceCPU, component, advanced) cpuLimits := getResource(ResourceLimits, corev1.ResourceCPU, component, advanced) memoryRequests := getResource(ResourceRequests, corev1.ResourceMemory, component, advanced) @@ -1133,6 +1166,7 @@ func SetOperandNames(c client.Client) error { operandNames[ObservatoriumOperator] = GetOperandNamePrefix() + ObservatoriumOperator operandNames[Observatorium] = GetDefaultCRName() operandNames[ObservatoriumAPI] = GetOperandNamePrefix() + ObservatoriumAPI + operandNames[MultiClusterObservabilityAddon] = GetOperandNamePrefix() + MultiClusterObservabilityAddon // Check if the Observatorium CR already exists opts := &client.ListOptions{ @@ -1156,6 +1190,7 @@ func SetOperandNames(c client.Client) error { operandNames[ObservatoriumOperator] = ObservatoriumOperator operandNames[Observatorium] = observatorium.Name operandNames[ObservatoriumAPI] = observatorium.Name + "-" + ObservatoriumAPI + operandNames[MultiClusterObservabilityAddon] = MultiClusterObservabilityAddon } break } @@ -1238,7 +1273,8 @@ func GetMulticloudConsoleHost(client client.Client, isStandalone bool) (string, found := &routev1.Route{} err := client.Get(context.TODO(), types.NamespacedName{ - Name: MulticloudConsoleRouteName, Namespace: namespace}, found) + Name: MulticloudConsoleRouteName, Namespace: namespace, + }, found) if err != nil { return "", err } diff --git a/operators/multiclusterobservability/pkg/rendering/renderer.go b/operators/multiclusterobservability/pkg/rendering/renderer.go index 6a19632d3e..bc7f4681d1 100644 --- a/operators/multiclusterobservability/pkg/rendering/renderer.go +++ b/operators/multiclusterobservability/pkg/rendering/renderer.go @@ -31,6 +31,7 @@ type MCORenderer struct { renderAlertManagerFns map[string]rendererutil.RenderFn renderThanosFns map[string]rendererutil.RenderFn renderProxyFns map[string]rendererutil.RenderFn + renderMCOAFns map[string]rendererutil.RenderFn } func NewMCORenderer(multipleClusterMonitoring *obv1beta2.MultiClusterObservability, kubeClient client.Client) *MCORenderer { @@ -43,6 +44,7 @@ func NewMCORenderer(multipleClusterMonitoring *obv1beta2.MultiClusterObservabili mcoRenderer.newAlertManagerRenderer() mcoRenderer.newThanosRenderer() mcoRenderer.newProxyRenderer() + mcoRenderer.newMCOARenderer() return mcoRenderer } @@ -105,6 +107,17 @@ func (r *MCORenderer) Render() ([]*unstructured.Unstructured, error) { } resources = append(resources, proxyResources...) + // load and render multicluster-observability-addon templates + mcoaTemplates, err := templates.GetOrLoadMCOATemplates(templatesutil.GetTemplateRenderer()) + if err != nil { + return nil, err + } + mcoaResources, err := r.renderMCOATemplates(mcoaTemplates, namespace, labels) + if err != nil { + return nil, err + } + resources = append(resources, mcoaResources...) + for idx := range resources { if resources[idx].GetKind() == "Deployment" { obj := util.GetK8sObj(resources[idx].GetKind()) diff --git a/operators/multiclusterobservability/pkg/rendering/renderer_mcoa.go b/operators/multiclusterobservability/pkg/rendering/renderer_mcoa.go new file mode 100644 index 0000000000..d17bc781bf --- /dev/null +++ b/operators/multiclusterobservability/pkg/rendering/renderer_mcoa.go @@ -0,0 +1,203 @@ +// Copyright (c) Red Hat, Inc. +// Copyright Contributors to the Open Cluster Management project +// Licensed under the Apache License 2.0 + +package rendering + +import ( + "fmt" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + "sigs.k8s.io/kustomize/api/resource" + + mcoconfig "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" + rendererutil "github.com/stolostron/multicluster-observability-operator/operators/pkg/rendering" + "github.com/stolostron/multicluster-observability-operator/operators/pkg/util" +) + +const ( + // AODC CustomizedVariable Names + namePlatformLogsCollection = "platformLogsCollection" + nameUserWorkloadLogsCollection = "userWorkloadLogsCollection" + nameUserWorkloadTracesCollection = "userWorkloadTracesCollection" + nameUserWorkloadInstrumentation = "userWorkloadInstrumentation" + + // AODC CustomizedVariable Values + clfV1 = "clusterlogforwarders.v1.logging.openshift.io" + otelV1alpa1 = "opentelemetrycollectors.v1alpha1.opentelemetry.io" + instrV1alpha1 = "instrumentations.v1alpha1.opentelemetry.io" +) + +func (r *MCORenderer) newMCOARenderer() { + r.renderMCOAFns = map[string]rendererutil.RenderFn{ + "AddonDeploymentConfig": r.renderAddonDeploymentConfig, + "ClusterManagementAddOn": r.renderClusterManagementAddOn, + "Deployment": r.renderMCOADeployment, + "ServiceAccount": r.renderer.RenderNamespace, + "ClusterRole": r.renderer.RenderClusterRole, + "ClusterRoleBinding": r.renderer.RenderClusterRoleBinding, + } +} + +func (r *MCORenderer) renderMCOADeployment(res *resource.Resource, + namespace string, labels map[string]string, +) (*unstructured.Unstructured, error) { + u, err := r.renderer.RenderNamespace(res, namespace, labels) + if err != nil { + return nil, err + } + obj := util.GetK8sObj(u.GetKind()) + err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, obj) + if err != nil { + return nil, err + } + crLabelKey := mcoconfig.GetCrLabelKey() + dep := obj.(*appsv1.Deployment) + dep.ObjectMeta.Labels[crLabelKey] = r.cr.Name + dep.Spec.Selector.MatchLabels[crLabelKey] = r.cr.Name + dep.Spec.Template.ObjectMeta.Labels[crLabelKey] = r.cr.Name + dep.Name = mcoconfig.GetOperandName(mcoconfig.MultiClusterObservabilityAddon) + dep.Spec.Replicas = mcoconfig.GetReplicas(mcoconfig.MultiClusterObservabilityAddon, r.cr.Spec.AdvancedConfig) + + spec := &dep.Spec.Template.Spec + + imagePullPolicy := mcoconfig.GetImagePullPolicy(r.cr.Spec) + spec.Containers[0].ImagePullPolicy = imagePullPolicy + spec.Containers[0].Resources = mcoconfig.GetResources(mcoconfig.MultiClusterObservabilityAddon, r.cr.Spec.AdvancedConfig) + spec.NodeSelector = r.cr.Spec.NodeSelector + spec.Tolerations = r.cr.Spec.Tolerations + spec.ImagePullSecrets = []corev1.LocalObjectReference{ + {Name: mcoconfig.GetImagePullSecret(r.cr.Spec)}, + } + + spec.Containers[0].Image = fmt.Sprintf("%s/%s:%s", + mcoconfig.MultiClusterObservabilityAddonImgRepo, + mcoconfig.MultiClusterObservabilityAddonImgName, + mcoconfig.MultiClusterObservabilityAddonImgTagSuffix, + ) + found, image := mcoconfig.ReplaceImage( + r.cr.Annotations, + mcoconfig.DefaultImgRepository+"/"+mcoconfig.MultiClusterObservabilityAddonImgName, + mcoconfig.MultiClusterObservabilityAddon) + if found { + spec.Containers[0].Image = image + } + + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return nil, err + } + + return &unstructured.Unstructured{Object: unstructuredObj}, nil +} + +func (r *MCORenderer) renderClusterManagementAddOn( + res *resource.Resource, + namespace string, + labels map[string]string, +) (*unstructured.Unstructured, error) { + m, err := res.Map() + if err != nil { + return nil, err + } + u := &unstructured.Unstructured{Object: m} + + cLabels := u.GetLabels() + if cLabels == nil { + cLabels = make(map[string]string) + } + for k, v := range labels { + cLabels[k] = v + } + u.SetLabels(cLabels) + + return u, nil +} + +func (r *MCORenderer) renderAddonDeploymentConfig(res *resource.Resource, namespace string, labels map[string]string) (*unstructured.Unstructured, error) { + m, err := res.Map() + if err != nil { + return nil, err + } + u := &unstructured.Unstructured{Object: m} + + if cs := r.cr.Spec.Capabilities; cs != nil { + var aodc *addonapiv1alpha1.AddOnDeploymentConfig + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, aodc); err != nil { + return nil, err + } + + appendCustomVar := func(aodc *addonapiv1alpha1.AddOnDeploymentConfig, name, value string) { + aodc.Spec.CustomizedVariables = append( + aodc.Spec.CustomizedVariables, + addonapiv1alpha1.CustomizedVariable{Name: name, Value: value}, + ) + } + + if cs.Platform != nil { + if cs.Platform.Logs.Enabled { + appendCustomVar(aodc, namePlatformLogsCollection, clfV1) + } + } + + if cs.UserWorkloads != nil { + if cs.UserWorkloads.Logs.ClusterLogForwarder.Enabled { + appendCustomVar(aodc, nameUserWorkloadLogsCollection, clfV1) + } + if cs.UserWorkloads.Traces.OpenTelemetryCollector.Enabled { + appendCustomVar(aodc, nameUserWorkloadTracesCollection, otelV1alpa1) + } + if cs.UserWorkloads.Traces.Instrumentation.Enabled { + appendCustomVar(aodc, nameUserWorkloadInstrumentation, instrV1alpha1) + } + } + + u.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(aodc) + if err != nil { + return nil, err + } + } + + cLabels := u.GetLabels() + if cLabels == nil { + cLabels = make(map[string]string) + } + for k, v := range labels { + cLabels[k] = v + } + u.SetLabels(cLabels) + + return u, nil +} + +func (r *MCORenderer) renderMCOATemplates(templates []*resource.Resource, + namespace string, labels map[string]string, +) ([]*unstructured.Unstructured, error) { + uobjs := []*unstructured.Unstructured{} + for _, template := range templates { + render, ok := r.renderMCOAFns[template.GetKind()] + if !ok { + m, err := template.Map() + if err != nil { + return []*unstructured.Unstructured{}, err + } + uobjs = append(uobjs, &unstructured.Unstructured{Object: m}) + continue + } + uobj, err := render(template.DeepCopy(), namespace, labels) + if err != nil { + return []*unstructured.Unstructured{}, err + } + if uobj == nil { + continue + } + uobjs = append(uobjs, uobj) + + } + + return uobjs, nil +} diff --git a/operators/multiclusterobservability/pkg/rendering/templates/templates.go b/operators/multiclusterobservability/pkg/rendering/templates/templates.go index 5259496333..e317ff923b 100644 --- a/operators/multiclusterobservability/pkg/rendering/templates/templates.go +++ b/operators/multiclusterobservability/pkg/rendering/templates/templates.go @@ -13,7 +13,7 @@ import ( ) // *Templates contains all kustomize resources. -var genericTemplates, grafanaTemplates, alertManagerTemplates, thanosTemplates, proxyTemplates, endpointObservabilityTemplates, prometheusTemplates []*resource.Resource +var genericTemplates, grafanaTemplates, alertManagerTemplates, thanosTemplates, proxyTemplates, endpointObservabilityTemplates, prometheusTemplates, mcoaTemplates []*resource.Resource // GetOrLoadGenericTemplates reads base manifest. func GetOrLoadGenericTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { @@ -96,6 +96,21 @@ func GetOrLoadProxyTemplates(r *templates.TemplateRenderer) ([]*resource.Resourc return proxyTemplates, nil } +// GetOrLoadMCOATemplates reads the rbac-query-proxy manifests. +func GetOrLoadMCOATemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { + if len(mcoaTemplates) > 0 { + return mcoaTemplates, nil + } + + basePath := path.Join(r.GetTemplatesPath(), "base") + + // add mcoa templates + if err := r.AddTemplateFromPath(basePath+"/multicluster-observability-addon", &mcoaTemplates); err != nil { + return mcoaTemplates, err + } + return mcoaTemplates, nil +} + // GetEndpointObservabilityTemplates reads endpoint-observability manifest. func GetOrLoadEndpointObservabilityTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { if len(endpointObservabilityTemplates) > 0 { @@ -136,4 +151,5 @@ func ResetTemplates() { thanosTemplates = nil proxyTemplates = nil endpointObservabilityTemplates = nil + mcoaTemplates = nil }