diff --git a/controllers/monitor/builder/builder.go b/controllers/monitor/builder/builder.go index 81c43eb7b0ee..ae4f2abe5c47 100644 --- a/controllers/monitor/builder/builder.go +++ b/controllers/monitor/builder/builder.go @@ -64,6 +64,7 @@ func BuildFromCUEForOTel(tplName string, fillMap map[string]any, lookupKey strin } value := cueValue.Value.LookupPath(cue.ParsePath(lookupKey)) + bytes, err := value.MarshalJSON() if err != nil { return nil, err diff --git a/controllers/monitor/builder/cue/exporter/prometheus.cue b/controllers/monitor/builder/cue/exporter/prometheus.cue index 4414a7efb354..4dfc3ae1508f 100644 --- a/controllers/monitor/builder/cue/exporter/prometheus.cue +++ b/controllers/monitor/builder/cue/exporter/prometheus.cue @@ -28,7 +28,7 @@ output: { endpoint: parameters.endpoint send_timestamps: parameters.send_timestamps metric_expiration: parameters.metric_expiration - enable_open_metrics: prarameters.enable_open_metrics + enable_open_metrics: parameters.enable_open_metrics resource_to_telemetry_conversion: enabled: parameters.resource_to_telemetry_conversion_enabled } diff --git a/controllers/monitor/builder/cue/extension/apecloud_engine_observer.cue b/controllers/monitor/builder/cue/extension/apecloud_engine_observer.cue deleted file mode 100644 index e479703ee0d7..000000000000 --- a/controllers/monitor/builder/cue/extension/apecloud_engine_observer.cue +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2022-2023 ApeCloud Co., Ltd -// -// This file is part of KubeBlocks project -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -parameters: { - pod_observer: *"apecloud_k8s_observer" | string - container_observer: *"runtime_container" | string - scraper_config_file: *"/opt/oteld/etc/scraper.yaml" | string -} - - - -output: - apecloud_engine_observer: { - pod_observer: parameters.pod_observer - container_observer: parameters.container_observer - scraper_config_file: parameters.scraper_config_file - } - diff --git a/controllers/monitor/builder/cue/extension/runtime_container.cue b/controllers/monitor/builder/cue/extension/extensions.cue similarity index 55% rename from controllers/monitor/builder/cue/extension/runtime_container.cue rename to controllers/monitor/builder/cue/extension/extensions.cue index 6cf883e1f6a5..46b25461b507 100644 --- a/controllers/monitor/builder/cue/extension/runtime_container.cue +++ b/controllers/monitor/builder/cue/extension/extensions.cue @@ -20,11 +20,34 @@ parameters: { container_runtime_type: *"containerd" | string } - -output: - runtime_contaienr: { - enable: parameters.enable - container_runtime_type: parameters.container_runtime_type +output: { + extensions: { + memory_ballast: + size_mib: 32 + apecloud_k8s_observer: { + auth_type: "kubeConfig" + node: "${env:NODE_NAME}" + observe_pods: true + observe_nodes: false + } + "apecloud_k8s_observer/node": { + auth_type: "kubeConfig" + node: "${env:NODE_NAME}" + observe_pods: false + observe_nodes: true + } + runtime_container: { + enable: true + auth_type: "kubeConfig" + kubernetes_node: "${env:NODE_NAME}" + } + apecloud_engine_observer: { + pod_observer: "apecloud_k8s_observer" + container_observer: "runtime_container" + scraper_config_file: "/tmp/oteld_test_work/kb_engine.yaml" + } } +} + diff --git a/controllers/monitor/builder/cue/processor/processors.cue b/controllers/monitor/builder/cue/processor/processors.cue new file mode 100644 index 000000000000..37cfe2b34dcf --- /dev/null +++ b/controllers/monitor/builder/cue/processor/processors.cue @@ -0,0 +1,6 @@ +output: + memory_limiter:{ + limit_mib: 512 + spike_limit_mib: 128 + check_interval: "10s" + } diff --git a/controllers/monitor/builder/cue/receiver/metrics/apecloudkubeletstats.cue b/controllers/monitor/builder/cue/receiver/metrics/apecloudkubeletstats.cue index deada084831e..65a10461f56a 100644 --- a/controllers/monitor/builder/cue/receiver/metrics/apecloudkubeletstats.cue +++ b/controllers/monitor/builder/cue/receiver/metrics/apecloudkubeletstats.cue @@ -16,23 +16,23 @@ // along with this program. If not, see . parameters: { - auth_type: *"service_account" | string - collection_interval: *"10s" | string - endpoint: *"http://localhost:10255" | string + auth_type: *"serviceAccount" | string + collection_interval: *"15s" | string + endpoint: *"`endpoint`:`kubelet_endpoint_port`" | string } output: apecloudkubeletstats: { - auth_type: parameters.auth_type - collection_interval: parameters.collection_interval - endpoint: parameters.endpoint - extra_metadata_labels: - - k8s.volume.type - - kubeblocks - metric_groups: - - container - - pod - - volume + rule: "type == \"k8s.node\"" + config: { + auth_type: parameters.auth_type + collection_interval: parameters.collection_interval + endpoint: parameters.endpoint + extra_metadata_labels: ["k8s.volume.type", "kubeblocks"] + metric_groups: ["container", "pod", "volume"] + resource_attributes: + receiver: "apecloudkubeletstats" + } } diff --git a/controllers/monitor/builder/cue/receiver/metrics/apecloudmysql.cue b/controllers/monitor/builder/cue/receiver/metrics/apecloudmysql.cue index 422ceebe8696..80366f52dfab 100644 --- a/controllers/monitor/builder/cue/receiver/metrics/apecloudmysql.cue +++ b/controllers/monitor/builder/cue/receiver/metrics/apecloudmysql.cue @@ -16,21 +16,26 @@ // along with this program. If not, see . parameters: { - username: *"${env:MYSQL_USER}" | string - password: *"${env:MYSQL_PASSWORD}" | string + endpoint: *"`endpoint`:3306" | string + username: *"`envs[\"MYSQL_ROOT_USER\"]`" | string + password: *"`envs[\"MYSQL_ROOT_PASSWORD\"]" | string allow_native_passwords: *true | bool transport: *"tcp" | string - collection_interval: *"${env:COLLECTION_INTERVAL}" | string + collection_interval: *"`settings.CollectionInterval`" | string } - - output: apecloudmysql: { - username: parameters.username - password: parameters.password - allow_native_passwords: parameters.allow_native_passwords - transport: parameters.transport - collection_interval: parameters.collection_interval + rule: "type == \"pod\" && monitor_type == \"mysql\"" + config:{ + endpoint: parameters.endpoint + username: parameters.username + password: parameters.password + allow_native_passwords: parameters.allow_native_passwords + transport: parameters.transport + collection_interval: parameters.collection_interval + } + resource_attributes: + receiver: "apecloudmysql" } diff --git a/controllers/monitor/builder/cue/receiver/metrics/apecloudnode.cue b/controllers/monitor/builder/cue/receiver/metrics/apecloudnode.cue index 7baeca014cbe..05606294925b 100644 --- a/controllers/monitor/builder/cue/receiver/metrics/apecloudnode.cue +++ b/controllers/monitor/builder/cue/receiver/metrics/apecloudnode.cue @@ -22,6 +22,10 @@ parameters: { output: apecloudnode: { - collection_interval: parameters.collection_interval + rule: "type == \"k8s.node\"" + config: + collection_interval: parameters.collection_interval + resource_attributes: + receiver: "apecloudnode" } diff --git a/controllers/monitor/builder/cue/receiver/resource_attributes.cue b/controllers/monitor/builder/cue/receiver/resource_attributes.cue new file mode 100644 index 000000000000..416eb49d7024 --- /dev/null +++ b/controllers/monitor/builder/cue/receiver/resource_attributes.cue @@ -0,0 +1,22 @@ +output: + resource_attributes: + pod: { + app_kubernetes_io_component: "`labels[\"app.kubernetes.io/component\"]`" + app_kubernetes_io_instance: "`labels[\"app.kubernetes.io/instance\"]`" + app_kubernetes_io_managed_by: "`labels[\"app.kubernetes.io/managed-by\"]`" + app_kubernetes_io_name: "`labels[\"app.kubernetes.io/name\"]`" + app_kubernetes_io_version: "`labels[\"app.kubernetes.io/version\"]`" + apps_kubeblocks_io_component_name: "`labels[\"apps.kubeblocks.io/component-name\"]`" + node: "${env:NODE_NAME}" + namespace: "`namespace`" + pod: "`name`" + job: "oteld-app" + } + "k8s.node": { + kubernetes_io_arch: "`labels[\"kubernetes.io/arch\"]`" + kubernetes_io_hostname: "`labels[\"kubernetes.io/hostname\"]`" + kubernetes_io_os: "`labels[\"kubernetes.io/os\"]`" + node: "`name`" + hostname: "`hostname`" + job: "oteld-system" + } diff --git a/controllers/monitor/builder/cue/service/service.cue b/controllers/monitor/builder/cue/service/service.cue new file mode 100644 index 000000000000..b855d7a55d6c --- /dev/null +++ b/controllers/monitor/builder/cue/service/service.cue @@ -0,0 +1,16 @@ +parameters: { + logLevel: *"debug" | string + metricsPort: *6668 | int +} + +output: + telemetry: { + logs: + level: parameters.logLevel + metrics: + address: "${env:HOST_IP}:" + "\(parameters.metricsPort)" + resource: + node: "${env:NODE_NAME}" + job: "oteld-telemetry" + } + extensions: ["memory_ballast", "apecloud_k8s_observer", "apecloud_k8s_observer/node", "runtime_container", "apecloud_engine_observer"] \ No newline at end of file diff --git a/controllers/monitor/builder/otel_config_test.go b/controllers/monitor/builder/otel_config_test.go deleted file mode 100644 index 4ef692a68a2f..000000000000 --- a/controllers/monitor/builder/otel_config_test.go +++ /dev/null @@ -1,123 +0,0 @@ -/* -Copyright (C) 2022-2023 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package builder - -import ( - "github.com/apecloud/kubeblocks/apis/monitor/v1alpha1" - . "github.com/onsi/ginkgo/v2" -) - -var _ = Describe("monitor_controller", func() { - //var ( - // logsExporterList v1alpha1.LogsExporterSinkList - // metricsExporterList v1alpha1.MetricsExporterSinkList - // datasourceList v1alpha1.CollectorDataSourceList - //) - // - //BeforeEach(func() { - // logsExporterList = fakeLogsExporterSinkList() - // metricsExporterList = fakeMetricsExporterSinkList() - // datasourceList = fakeCollectorDataSourceList() - //}) - // - //It("should generate config correctly from config yaml", func() { - // Eventually(func(g Gomega) { - // config, err := types.LoadConfig("./data/config_test.yaml") - // if err != nil { - // return - // } - // g.Expect(config).ShouldNot(BeNil()) - // }).Should(Succeed()) - //}) - // - //It("should generate oteld correctly", func() { - // - // instance := fakeOteldInstance() - // - // config, err := types.LoadConfig("./data/config_test.yaml") - // Expect(err).ShouldNot(HaveOccurred()) - // - // By("create cluster & clusterDef") - // cg := NewConfigGenerator(config) - // cfg := cg.GenerateOteldConfiguration(, &metricsExporterList, &logsExporterList) - // bytes, err := yaml.Marshal(cfg) - // Expect(err).ShouldNot(HaveOccurred()) - // Expect(len(bytes) > 0).Should(BeTrue()) - // Expect(true).Should(BeTrue()) - //}) - -}) - -func fakeCollectorDataSourceList() v1alpha1.CollectorDataSourceList { - return v1alpha1.CollectorDataSourceList{ - Items: []v1alpha1.CollectorDataSource{ - { - Spec: v1alpha1.CollectorDataSourceSpec{ - Type: v1alpha1.MetricsDatasourceType, - ExporterRef: v1alpha1.ExporterRef{ExporterNames: []string{"prometheus"}}, - DataSourceList: []v1alpha1.DataSource{ - {Name: "apecloudmysql"}, - }, - }, - }, - { - Spec: v1alpha1.CollectorDataSourceSpec{ - Type: v1alpha1.LogsDataSourceType, - ExporterRef: v1alpha1.ExporterRef{ExporterNames: []string{"loki"}}, - DataSourceList: []v1alpha1.DataSource{ - {Name: "mysql"}, - }, - }, - }, - }, - } -} - -func fakeMetricsExporterSinkList() v1alpha1.MetricsExporterSinkList { - return v1alpha1.MetricsExporterSinkList{ - Items: []v1alpha1.MetricsExporterSink{ - { - Spec: v1alpha1.MetricsExporterSinkSpec{ - Type: v1alpha1.PrometheusSinkType, MetricsSinkSource: v1alpha1.MetricsSinkSource{ - PrometheusConfig: &v1alpha1.PrometheusConfig{ServiceRef: v1alpha1.ServiceRef{Endpoint: "test"}}, - }}, - }, - }, - } -} - -func fakeLogsExporterSinkList() v1alpha1.LogsExporterSinkList { - return v1alpha1.LogsExporterSinkList{ - Items: []v1alpha1.LogsExporterSink{ - { - Spec: v1alpha1.LogsExporterSinkSpec{ - Type: v1alpha1.LokiSinkType, SinkSource: v1alpha1.SinkSource{ - LokiConfig: &v1alpha1.LokiConfig{ServiceRef: v1alpha1.ServiceRef{Endpoint: "test"}}, - }}, - }, - { - Spec: v1alpha1.LogsExporterSinkSpec{ - Type: v1alpha1.S3SinkType, SinkSource: v1alpha1.SinkSource{ - LokiConfig: &v1alpha1.LokiConfig{ServiceRef: v1alpha1.ServiceRef{Endpoint: "test"}}, - }}, - }, - }, - } -} diff --git a/controllers/monitor/reconcile/oteld.go b/controllers/monitor/reconcile/oteld.go index 5a45232982ee..a872d89b2c41 100644 --- a/controllers/monitor/reconcile/oteld.go +++ b/controllers/monitor/reconcile/oteld.go @@ -70,10 +70,11 @@ func buildOteldInstance( datasources *v1alpha1.CollectorDataSourceList, templates *v1alpha1.OTeldCollectorTemplateList, ) error { - err := mergeDatasourceForPipline(reqCtx, datasources) + instanceMap, err := BuildInstanceMapForPipline(datasources) if err != nil { return err } + reqCtx.SetOteldInstanceMap(instanceMap) for _, template := range templates.Items { instance := reqCtx.GetOteldInstance(template.Spec.Mode) @@ -89,14 +90,15 @@ func buildOteldInstance( return nil } -func mergeDatasourceForPipline(reqCtx monitortype.ReconcileCtx, datasources *v1alpha1.CollectorDataSourceList) error { +func BuildInstanceMapForPipline(datasources *v1alpha1.CollectorDataSourceList) (map[v1alpha1.Mode]*monitortype.OteldInstance, error) { + instanceMap := map[v1alpha1.Mode]*monitortype.OteldInstance{} for _, dataSource := range datasources.Items { mode := dataSource.Spec.Mode if mode == "" { mode = DefaultMode } - oteldInstance := reqCtx.GetOteldInstance(mode) - if oteldInstance == nil { + oteldInstance, ok := instanceMap[mode] + if !ok { oteldInstance = monitortype.NewOteldInstance() } switch dataSource.Spec.Type { @@ -125,7 +127,7 @@ func mergeDatasourceForPipline(reqCtx monitortype.ReconcileCtx, datasources *v1a } oteldInstance.LogsPipline = append(oteldInstance.LogsPipline, pipline) } - reqCtx.SetOteldInstance(dataSource.Spec.Mode, oteldInstance) + instanceMap[dataSource.Spec.Mode] = oteldInstance } - return nil + return instanceMap, nil } diff --git a/controllers/monitor/reconcile/utils.go b/controllers/monitor/reconcile/utils.go index c22a2a92298d..c3030dad0dbe 100644 --- a/controllers/monitor/reconcile/utils.go +++ b/controllers/monitor/reconcile/utils.go @@ -215,7 +215,7 @@ func buildConfigMapForOteld(_ *types.Config, instance *types.OteldInstance, name constant.AppInstanceLabelKey: name, } - configData := gc.GenerateOteldConfiguration(instance, exporters.Metricsexporter, exporters.Logsexporter) + configData, _ := gc.GenerateOteldConfiguration(instance, exporters.Metricsexporter, exporters.Logsexporter) marshal, err := yaml.Marshal(configData) if err != nil { return nil, err @@ -241,7 +241,7 @@ func buildSecretForOteld(_ *types.Config, instance *types.OteldInstance, namespa constant.AppInstanceLabelKey: name, } - configData := gc.GenerateOteldConfiguration(instance, exporters.Metricsexporter, exporters.Logsexporter) + configData, _ := gc.GenerateOteldConfiguration(instance, exporters.Metricsexporter, exporters.Logsexporter) marshal, err := yaml.Marshal(configData) if err != nil { return nil, err diff --git a/controllers/monitor/types/otel_config.go b/controllers/monitor/types/otel_config.go index c2fe77eeb283..b2e6a125310e 100644 --- a/controllers/monitor/types/otel_config.go +++ b/controllers/monitor/types/otel_config.go @@ -16,6 +16,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ + package types import ( @@ -31,6 +32,9 @@ const ( ExtensionTplPattern = "extension/%s.cue" ExporterTplPattern = "exporter/%s.cue" ReceiverNamePattern = "receiver_creator/%s" + ServicePath = "service/service.cue" + + ExtensionPath = "extension/extensions.cue" ) type OteldConfigGenerater struct { @@ -41,51 +45,56 @@ func NewConfigGenerator() *OteldConfigGenerater { return &OteldConfigGenerater{cache: map[v1alpha1.Mode]yaml.MapSlice{}} } -func (cg *OteldConfigGenerater) GenerateOteldConfiguration( - instance *OteldInstance, - metricsExporterList []v1alpha1.MetricsExporterSink, - logsExporterList []v1alpha1.LogsExporterSink, -) yaml.MapSlice { +func (cg *OteldConfigGenerater) GenerateOteldConfiguration(instance *OteldInstance, metricsExporterList []v1alpha1.MetricsExporterSink, logsExporterList []v1alpha1.LogsExporterSink) (yaml.MapSlice, error) { if instance == nil || instance.OteldTemplate == nil { - return nil + return nil, nil } if cg.cache == nil && cg.cache[instance.OteldTemplate.Spec.Mode] != nil { - return cg.cache[instance.OteldTemplate.Spec.Mode] + return cg.cache[instance.OteldTemplate.Spec.Mode], nil } cfg := yaml.MapSlice{} - cfg, _ = cg.appendExtentions(cfg) - cfg = cg.appendReceiver(cfg, instance) - cfg = cg.appendProcessor(cfg) - cfg, _ = cg.appendExporter(cfg, metricsExporterList, logsExporterList) - cfg = cg.appendServices(cfg, instance) + var err error + cfg, err = cg.appendExtentions(cfg) + cfg, err = cg.appendReceiver(cfg, instance) + cfg, err = cg.appendProcessor(cfg) + cfg, err = cg.appendExporter(cfg, metricsExporterList, logsExporterList) + cfg, err = cg.appendServices(cfg, instance) + if err != nil { + return nil, err + } cg.cache[instance.OteldTemplate.Spec.Mode] = cfg - return cfg + return cfg, nil } -func (cg *OteldConfigGenerater) appendReceiver(cfg yaml.MapSlice, instance *OteldInstance) yaml.MapSlice { +func (cg *OteldConfigGenerater) appendReceiver(cfg yaml.MapSlice, instance *OteldInstance) (yaml.MapSlice, error) { receiverSlice := yaml.MapSlice{} creatorSlice, err := newReceiverCreatorSlice(instance) if err != nil { - return nil + return nil, err } receiverSlice = append(receiverSlice, creatorSlice...) - return append(cfg, yaml.MapItem{Key: "receivers", Value: receiverSlice}) + attributesSlice, err := buildSliceFromCUE("receiver/resource_attributes.cue", map[string]any{}) + if err != nil { + return nil, err + } + receiverSlice = append(receiverSlice, attributesSlice...) + return append(cfg, yaml.MapItem{Key: "receivers", Value: receiverSlice}), nil } func newReceiverCreatorSlice(instance *OteldInstance) (yaml.MapSlice, error) { creators := yaml.MapSlice{} - for index, pipline := range instance.MetricsPipline { - creator, err := newReceiverCreator(index, v1alpha1.MetricsDatasourceType, pipline.ReceiverMap) + for _, pipline := range instance.MetricsPipline { + creator, err := newReceiverCreator(pipline.Name, v1alpha1.MetricsDatasourceType, pipline.ReceiverMap) if err != nil { return nil, err } creators = append(creators, creator) } - for index, pipline := range instance.LogsPipline { - creator, err := newReceiverCreator(index, v1alpha1.LogsDataSourceType, pipline.ReceiverMap) + for _, pipline := range instance.LogsPipline { + creator, err := newReceiverCreator(pipline.Name, v1alpha1.LogsDataSourceType, pipline.ReceiverMap) if err != nil { return nil, err } @@ -94,13 +103,16 @@ func newReceiverCreatorSlice(instance *OteldInstance) (yaml.MapSlice, error) { return creators, nil } -func newReceiverCreator(index int, datasourceType v1alpha1.DataSourceType, receiverMap map[string]Receiver) (yaml.MapItem, error) { +func newReceiverCreator(name string, datasourceType v1alpha1.DataSourceType, receiverMap map[string]Receiver) (yaml.MapItem, error) { creator := yaml.MapSlice{} - creator = append(creator, yaml.MapItem{Key: "watch_observers", Value: []string{"apecloud_engine_observer"}}) + creator = append(creator, yaml.MapItem{Key: "watch_observers", Value: []string{"apecloud_engine_observer", "apecloud_k8s_observer/node"}}) receiverSlice := yaml.MapSlice{} for name, params := range receiverMap { tplName := fmt.Sprintf(CUEPathPattern, datasourceType, name) - valueMap := map[string]any{"collection_interval": params.CollectionInterval} + valueMap := map[string]any{} + if params.Parameter != "" { + valueMap["collection_interval"] = params.CollectionInterval + } builder.MergeValMapFromYamlStr(valueMap, params.Parameter) receivers, err := buildSliceFromCUE(tplName, valueMap) if err != nil { @@ -109,7 +121,7 @@ func newReceiverCreator(index int, datasourceType v1alpha1.DataSourceType, recei receiverSlice = append(receiverSlice, receivers...) } creator = append(creator, yaml.MapItem{Key: "receivers", Value: receiverSlice}) - return yaml.MapItem{Key: fmt.Sprintf(ReceiverNamePattern, datasourceType, index), Value: creator}, nil + return yaml.MapItem{Key: fmt.Sprintf(ReceiverNamePattern, name), Value: creator}, nil } func (cg *OteldConfigGenerater) appendExporter(cfg yaml.MapSlice, metricsExporters []v1alpha1.MetricsExporterSink, logsExporter []v1alpha1.LogsExporterSink) (yaml.MapSlice, error) { @@ -146,18 +158,24 @@ func (cg *OteldConfigGenerater) appendExporter(cfg yaml.MapSlice, metricsExporte return append(cfg, yaml.MapItem{Key: "exporters", Value: exporterSlice}), nil } -func (cg *OteldConfigGenerater) appendProcessor(cfg yaml.MapSlice) yaml.MapSlice { - // TODO - return cfg +func (cg *OteldConfigGenerater) appendProcessor(cfg yaml.MapSlice) (yaml.MapSlice, error) { + processorSlice, err := buildSliceFromCUE("processor/processors.cue", map[string]any{}) + if err != nil { + return nil, err + } + return append(cfg, yaml.MapItem{Key: "processors", Value: processorSlice}), nil } -func (cg *OteldConfigGenerater) appendServices(cfg yaml.MapSlice, instance *OteldInstance) yaml.MapSlice { +func (cg *OteldConfigGenerater) appendServices(cfg yaml.MapSlice, instance *OteldInstance) (yaml.MapSlice, error) { serviceSlice := yaml.MapSlice{} piplneItem := cg.buildPiplineItem(instance) serviceSlice = append(serviceSlice, piplneItem) - extensionItem := yaml.MapItem{Key: "extensions", Value: []string{"runtime_container", "apecloud_engine_observer"}} - serviceSlice = append(serviceSlice, extensionItem) - return append(cfg, yaml.MapItem{Key: "service", Value: serviceSlice}) + extensionSlice, err := buildSliceFromCUE(ServicePath, map[string]any{}) + if err != nil { + return nil, err + } + serviceSlice = append(serviceSlice, extensionSlice...) + return append(cfg, yaml.MapItem{Key: "service", Value: serviceSlice}), nil } func (cg *OteldConfigGenerater) buildPiplineItem(instance *OteldInstance) yaml.MapItem { @@ -168,9 +186,7 @@ func (cg *OteldConfigGenerater) buildPiplineItem(instance *OteldInstance) yaml.M metricsSlice := yaml.MapSlice{} for _, pipline := range instance.MetricsPipline { receiverSlice := []string{} - for _ = range pipline.ReceiverMap { - receiverSlice = append(receiverSlice, pipline.Name) - } + receiverSlice = append(receiverSlice, fmt.Sprintf(ReceiverNamePattern, pipline.Name)) metricsSlice = append(metricsSlice, yaml.MapItem{Key: "receivers", Value: receiverSlice}) exporterSlice := []string{} for name, _ := range pipline.ExporterMap { @@ -188,7 +204,7 @@ func (cg *OteldConfigGenerater) buildPiplineItem(instance *OteldInstance) yaml.M for _, pipline := range instance.LogsPipline { receiverSlice := []string{} for _ = range pipline.ReceiverMap { - receiverSlice = append(receiverSlice, pipline.Name) + receiverSlice = append(receiverSlice, fmt.Sprintf(ReceiverNamePattern, pipline.Name)) } logsSlice = append(logsSlice, yaml.MapItem{Key: "receivers", Value: receiverSlice}) exporterSlice := []string{} @@ -207,12 +223,7 @@ func (cg *OteldConfigGenerater) buildPiplineItem(instance *OteldInstance) yaml.M func (cg *OteldConfigGenerater) appendExtentions(cfg yaml.MapSlice) (yaml.MapSlice, error) { extensionSlice := yaml.MapSlice{} - extension, err := buildSliceFromCUE(fmt.Sprintf(ExtensionTplPattern, "apecloud_engine_observer"), map[string]any{}) - if err != nil { - return nil, err - } - extensionSlice = append(extensionSlice, extension...) - extension, err = buildSliceFromCUE(fmt.Sprintf(ExtensionTplPattern, "runtime_container"), map[string]any{}) + extension, err := buildSliceFromCUE(ExtensionPath, map[string]any{}) if err != nil { return nil, err } diff --git a/controllers/monitor/types/otel_config_test.go b/controllers/monitor/types/otel_config_test.go new file mode 100644 index 000000000000..3e52689fe0ec --- /dev/null +++ b/controllers/monitor/types/otel_config_test.go @@ -0,0 +1,124 @@ +/* +Copyright (C) 2022-2023 ApeCloud Co., Ltd + +This file is part of KubeBlocks project + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ + +package types + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/apecloud/kubeblocks/apis/monitor/v1alpha1" + "gopkg.in/yaml.v2" +) + +var _ = Describe("monitor_controller", func() { + var ( + logsExporterList v1alpha1.LogsExporterSinkList + metricsExporterList v1alpha1.MetricsExporterSinkList + ) + + BeforeEach(func() { + logsExporterList = fakeLogsExporterSinkList() + metricsExporterList = fakeMetricsExporterSinkList() + }) + + It("should generate config correctly from config yaml", func() { + Eventually(func(g Gomega) { + config, err := LoadConfig("./data/config_test.yaml") + if err != nil { + return + } + g.Expect(config).ShouldNot(BeNil()) + }).Should(Succeed()) + }) + + It("should generate oteld correctly", func() { + instance := fakeInstance() + + cg := NewConfigGenerator() + cfg, err := cg.GenerateOteldConfiguration(instance, metricsExporterList.Items, logsExporterList.Items) + Expect(err).ShouldNot(HaveOccurred()) + bytes, err := yaml.Marshal(cfg) + Expect(err).ShouldNot(HaveOccurred()) + Expect(len(bytes) > 0).Should(BeTrue()) + Expect(true).Should(BeTrue()) + }) + +}) + +func fakeInstance() *OteldInstance { + return &OteldInstance{ + MetricsPipline: []Pipline{ + { + Name: "metrics", + ReceiverMap: map[string]Receiver{ + "apecloudmysql": {}, + "apecloudkubeletstats": {}, + "apecloudnode": {}, + }, + ProcessorMap: map[string]bool{}, + ExporterMap: map[string]bool{ + "prometheus": true, + }, + }, + }, + OteldTemplate: &v1alpha1.OTeldCollectorTemplate{ + Spec: v1alpha1.OTeldCollectorTemplateSpec{ + Mode: v1alpha1.ModeDaemonSet, + }, + }, + } +} + +func fakeCollectorDataSourceList() v1alpha1.CollectorDataSourceList { + return v1alpha1.CollectorDataSourceList{ + Items: []v1alpha1.CollectorDataSource{ + { + Spec: v1alpha1.CollectorDataSourceSpec{ + Type: v1alpha1.MetricsDatasourceType, + ExporterRef: v1alpha1.ExporterRef{ExporterNames: []string{"prometheus"}}, + DataSourceList: []v1alpha1.DataSource{ + {Name: "apecloudmysql"}, + {Name: "apecloudkubeletstats"}, + {Name: "apecloudnode"}, + }, + }, + }, + }, + } +} + +func fakeMetricsExporterSinkList() v1alpha1.MetricsExporterSinkList { + return v1alpha1.MetricsExporterSinkList{ + Items: []v1alpha1.MetricsExporterSink{ + { + Spec: v1alpha1.MetricsExporterSinkSpec{ + Type: v1alpha1.PrometheusSinkType, MetricsSinkSource: v1alpha1.MetricsSinkSource{ + PrometheusConfig: &v1alpha1.PrometheusConfig{ServiceRef: v1alpha1.ServiceRef{Endpoint: "test"}}, + }}, + }, + }, + } +} + +func fakeLogsExporterSinkList() v1alpha1.LogsExporterSinkList { + return v1alpha1.LogsExporterSinkList{ + Items: []v1alpha1.LogsExporterSink{}, + } +} diff --git a/controllers/monitor/types/types.go b/controllers/monitor/types/types.go index 2b63bee65a9f..53cfbc7f3e78 100644 --- a/controllers/monitor/types/types.go +++ b/controllers/monitor/types/types.go @@ -132,6 +132,10 @@ func (c *ReconcileCtx) VerifyOteldInstance(metricsExporterList *v1alpha1.Metrics return nil } +func (c *ReconcileCtx) SetOteldInstanceMap(instanceMap map[v1alpha1.Mode]*OteldInstance) { + c.OteldInstanceMap = instanceMap +} + type ReconcileTask interface { Do(reqCtx ReconcileCtx) error }