diff --git a/go.mod b/go.mod index 5f6a8a36a..4a969e647 100644 --- a/go.mod +++ b/go.mod @@ -65,6 +65,7 @@ require ( github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/go-errors/errors v1.5.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/analysis v0.25.0 // indirect @@ -110,6 +111,7 @@ require ( github.com/moby/spdystream v0.5.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/muhlemmer/gu v0.3.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect @@ -136,6 +138,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/xlab/treeprint v1.2.0 // indirect github.com/zitadel/oidc/v3 v3.47.4 // indirect github.com/zitadel/schema v1.3.2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect @@ -181,6 +184,8 @@ require ( k8s.io/klog/v2 v2.140.0 // indirect k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/kustomize/api v0.21.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.21.1 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/go.sum b/go.sum index dfa3c6962..a4b31ae03 100644 --- a/go.sum +++ b/go.sum @@ -105,6 +105,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -262,6 +264,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -384,6 +388,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -392,6 +397,8 @@ github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/zitadel/oidc/v3 v3.47.4 h1:aRNmqY5XkVNUybkMUO+s1QXxjja0M2hoschoqMNgn6U= github.com/zitadel/oidc/v3 v3.47.4/go.mod h1:XxFh0666HRXycyrKmono+3gY0RACpYJLgy4r/+kliKY= github.com/zitadel/schema v1.3.2 h1:gfJvt7dOMfTmxzhscZ9KkapKo3Nei3B6cAxjav+lyjI= @@ -518,6 +525,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= @@ -544,6 +552,11 @@ sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4i sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/kustomize v1.0.11/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/kustomize/api v0.21.1 h1:lzqbzvz2CSvsjIUZUBNFKtIMsEw7hVLJp0JeSIVmuJs= +sigs.k8s.io/kustomize/api v0.21.1/go.mod h1:f3wkKByTrgpgltLgySCntrYoq5d3q7aaxveSagwTlwI= +sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7fI= +sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= diff --git a/pkg/controllers/observability/overlay.go b/pkg/controllers/observability/overlay.go new file mode 100644 index 000000000..11410c105 --- /dev/null +++ b/pkg/controllers/observability/overlay.go @@ -0,0 +1,168 @@ +package observability + +import ( + "fmt" + "io/fs" + "path/filepath" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/kustomize/api/krusty" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filesys" + sigsyaml "sigs.k8s.io/yaml" + + "github.com/rhobs/observability-operator/stack" +) + +const ( + overlayDir = "/stack/generated" + stackRoot = "/stack" +) + +type Overlay struct { + namespace string + components []string + patches map[string][]byte + resources map[string][]byte +} + +func NewOverlay(namespace string) *Overlay { + return &Overlay{ + namespace: namespace, + components: nil, + patches: make(map[string][]byte), + resources: make(map[string][]byte), + } +} + +func (o *Overlay) AddComponent(relPath string) { + o.components = append(o.components, relPath) +} + +func (o *Overlay) AddPatch(path string, content []byte) { + o.patches[path] = content +} + +func (o *Overlay) AddResource(path string, content []byte) { + o.resources[path] = content +} + +func (o *Overlay) Build() ([]client.Object, error) { + fSys := filesys.MakeFsInMemory() + + if err := copyEmbeddedFS(fSys, stack.FS, stackRoot); err != nil { + return nil, fmt.Errorf("loading embedded stack manifests: %w", err) + } + + if err := o.writeOverlay(fSys); err != nil { + return nil, fmt.Errorf("writing overlay: %w", err) + } + + k := krusty.MakeKustomizer(krusty.MakeDefaultOptions()) + resMap, err := k.Run(fSys, overlayDir) + if err != nil { + return nil, fmt.Errorf("kustomize build: %w", err) + } + + var objects []client.Object + for _, res := range resMap.Resources() { + jsonBytes, err := res.MarshalJSON() + if err != nil { + return nil, fmt.Errorf("marshaling resource %s: %w", res.CurId(), err) + } + obj := &unstructured.Unstructured{} + if err := obj.UnmarshalJSON(jsonBytes); err != nil { + return nil, fmt.Errorf("unmarshaling resource %s: %w", res.CurId(), err) + } + objects = append(objects, obj) + } + return objects, nil +} + +func (o *Overlay) writeOverlay(fSys filesys.FileSystem) error { + if err := fSys.MkdirAll(overlayDir); err != nil { + return err + } + + // Build the kustomization + kust := types.Kustomization{ + TypeMeta: types.TypeMeta{ + APIVersion: "kustomize.config.k8s.io/v1beta1", + Kind: "Kustomization", + }, + Components: o.components, + Transformers: []string{"namespace-transformer.yaml"}, + } + + for path := range o.resources { + kust.Resources = append(kust.Resources, path) + } + for path := range o.patches { + kust.Patches = append(kust.Patches, types.Patch{Path: path}) + } + + kustYAML, err := sigsyaml.Marshal(kust) + if err != nil { + return fmt.Errorf("marshaling kustomization: %w", err) + } + if err := fSys.WriteFile(filepath.Join(overlayDir, "kustomization.yaml"), kustYAML); err != nil { + return err + } + + // Write the namespace transformer + nsTransformer := fmt.Sprintf(`apiVersion: builtin +kind: NamespaceTransformer +metadata: + name: namespace-transformer +namespace: %s +unsetOnly: true +setRoleBindingSubjects: allServiceAccounts +`, o.namespace) + if err := fSys.WriteFile(filepath.Join(overlayDir, "namespace-transformer.yaml"), []byte(nsTransformer)); err != nil { + return err + } + + // Write patch and resource files + for path, content := range o.patches { + fullPath := filepath.Join(overlayDir, path) + if err := fSys.MkdirAll(filepath.Dir(fullPath)); err != nil { + return err + } + if err := fSys.WriteFile(fullPath, content); err != nil { + return err + } + } + for path, content := range o.resources { + fullPath := filepath.Join(overlayDir, path) + if err := fSys.MkdirAll(filepath.Dir(fullPath)); err != nil { + return err + } + if err := fSys.WriteFile(fullPath, content); err != nil { + return err + } + } + + return nil +} + +func jsonToYAML(j []byte) ([]byte, error) { + return sigsyaml.JSONToYAML(j) +} + +func copyEmbeddedFS(fSys filesys.FileSystem, embedded fs.FS, root string) error { + return fs.WalkDir(embedded, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + target := filepath.Join(root, path) + if d.IsDir() { + return fSys.MkdirAll(target) + } + data, err := fs.ReadFile(embedded, path) + if err != nil { + return err + } + return fSys.WriteFile(target, data) + }) +} diff --git a/pkg/controllers/observability/reconcilers.go b/pkg/controllers/observability/reconcilers.go index 4a6e3ef73..9c3348680 100644 --- a/pkg/controllers/observability/reconcilers.go +++ b/pkg/controllers/observability/reconcilers.go @@ -59,7 +59,7 @@ func getReconcilers(ctx context.Context, k8sClient client.Client, k8sReader clie otelSubs := subscription(opts.OpenTelemetryOperator) tempoSubs := subscription(opts.TempoOperator) - // instance objects + // OTEL collector and its RBAC (not yet converted to overlay) otelCol, err := otelCollector(instance) if err != nil { return nil, fmt.Errorf("failed to create OpenTelemetryCollector: %w", err) @@ -68,26 +68,25 @@ func getReconcilers(ctx context.Context, k8sClient client.Client, k8sReader clie otelcolRBAC, otelcolRBACBinding := otelCollectorComponentsRBAC(instance) instanceObjects = append(instanceObjects, otelcolRBAC) instanceObjects = append(instanceObjects, otelcolRBACBinding) - instanceObjects = append(instanceObjects, tempoStack(instance)) + otelcolTempoRBAC, otelcolTempoRBACBinding := otelCollectorTempoRBAC(instance) + instanceObjects = append(instanceObjects, otelcolTempoRBAC) + instanceObjects = append(instanceObjects, otelcolTempoRBACBinding) - secrets, err := tempoStackSecrets(ctx, k8sClient, k8sReader, *instance) - if err != nil { - return nil, fmt.Errorf("failed to create TempoStack secret: %w", err) - } - if secrets.objectStorage != nil { - instanceObjects = append(instanceObjects, secrets.objectStorage) - } - if secrets.objectStorageTLSSecret != nil { - instanceObjects = append(instanceObjects, secrets.objectStorageTLSSecret) + // TempoStack, secrets, and UIPlugin via kustomize overlay + overlay := NewOverlay(instance.Namespace) + if err := addTempoStack(overlay, instance); err != nil { + return nil, fmt.Errorf("failed to build TempoStack overlay: %w", err) } - if secrets.objectStorageCAConfigMap != nil { - instanceObjects = append(instanceObjects, secrets.objectStorageCAConfigMap) + if err := addTempoSecrets(ctx, overlay, k8sClient, k8sReader, instance); err != nil { + return nil, fmt.Errorf("failed to build TempoStack secrets: %w", err) } + addUIPlugin(overlay) - otelcolTempoRBAC, otelcolTempoRBACBinding := otelCollectorTempoRBAC(instance) - instanceObjects = append(instanceObjects, otelcolTempoRBAC) - instanceObjects = append(instanceObjects, otelcolTempoRBACBinding) - instanceObjects = append(instanceObjects, uiPlugin()) + overlayObjects, err := overlay.Build() + if err != nil { + return nil, fmt.Errorf("failed to build kustomize overlay: %w", err) + } + instanceObjects = append(instanceObjects, overlayObjects...) if instance.ObjectMeta.DeletionTimestamp != nil { for _, obj := range instanceObjects { diff --git a/pkg/controllers/observability/reconcilers_test.go b/pkg/controllers/observability/reconcilers_test.go index d41c3cf8a..455182c6d 100644 --- a/pkg/controllers/observability/reconcilers_test.go +++ b/pkg/controllers/observability/reconcilers_test.go @@ -13,6 +13,7 @@ import ( rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -37,13 +38,12 @@ func TestGetReconcilers(t *testing.T) { mockClient: func() *MockClient { mockClient := &MockClient{} mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil) + // OTEL resources (still typed) mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil) + // Overlay resources (TempoStack, UIPlugin, RBAC, Secret) + mockClient.On("Patch", context.Background(), mock.IsType(&unstructured.Unstructured{}), mock.Anything, mock.Anything).Return(nil) return mockClient }, instance: &obsv1alpha1.ObservabilityInstaller{ @@ -70,14 +70,12 @@ func TestGetReconcilers(t *testing.T) { mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil) mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&corev1.Secret{}), mock.Anything).Return(nil) mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&corev1.ConfigMap{}), mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil) + // OTEL resources (still typed) mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&corev1.ConfigMap{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil) + // Overlay resources (TempoStack, UIPlugin, RBAC, Secrets, ConfigMaps) + mockClient.On("Patch", context.Background(), mock.IsType(&unstructured.Unstructured{}), mock.Anything, mock.Anything).Return(nil) return mockClient }, instance: &obsv1alpha1.ObservabilityInstaller{ @@ -121,13 +119,12 @@ func TestGetReconcilers(t *testing.T) { mockClient: func() *MockClient { mockClient := &MockClient{} mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything).Return(nil) + // OTEL resources (still typed) mockClient.On("Delete", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Delete", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Delete", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil) + // Overlay resources + mockClient.On("Delete", context.Background(), mock.IsType(&unstructured.Unstructured{}), mock.Anything, mock.Anything).Return(nil) return mockClient }, instance: &obsv1alpha1.ObservabilityInstaller{ @@ -155,13 +152,12 @@ func TestGetReconcilers(t *testing.T) { mockClient := &MockClient{} mockClient.On("Delete", context.Background(), mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil) mockClient.On("Delete", context.Background(), mock.IsType(&olmv1alpha1.ClusterServiceVersion{}), mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything).Return(nil) + // OTEL resources (still typed) mockClient.On("Delete", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Delete", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Delete", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil) + // Overlay resources + mockClient.On("Delete", context.Background(), mock.IsType(&unstructured.Unstructured{}), mock.Anything, mock.Anything).Return(nil) return mockClient }, instance: &obsv1alpha1.ObservabilityInstaller{ @@ -184,13 +180,12 @@ func TestGetReconcilers(t *testing.T) { name: "tracing capability enabled, subscription already installed", mockClient: func() *MockClient { mockClient := &MockClient{} - mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil) + // OTEL resources (still typed) mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil) + // Overlay resources + mockClient.On("Patch", context.Background(), mock.IsType(&unstructured.Unstructured{}), mock.Anything, mock.Anything).Return(nil) return mockClient }, instance: &obsv1alpha1.ObservabilityInstaller{ @@ -229,13 +224,12 @@ func TestGetReconcilers(t *testing.T) { mockClient := &MockClient{} mockClient.On("Delete", context.Background(), mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil) mockClient.On("Delete", context.Background(), mock.IsType(&olmv1alpha1.ClusterServiceVersion{}), mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything).Return(nil) + // OTEL resources (still typed) mockClient.On("Delete", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Delete", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil) mockClient.On("Delete", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil) - mockClient.On("Delete", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil) + // Overlay resources + mockClient.On("Delete", context.Background(), mock.IsType(&unstructured.Unstructured{}), mock.Anything, mock.Anything).Return(nil) return mockClient }, instance: &obsv1alpha1.ObservabilityInstaller{ diff --git a/pkg/controllers/observability/tempo_components.go b/pkg/controllers/observability/tempo_components.go index 83b6260d3..711c2a6bc 100644 --- a/pkg/controllers/observability/tempo_components.go +++ b/pkg/controllers/observability/tempo_components.go @@ -2,6 +2,7 @@ package observability import ( "context" + "encoding/json" "fmt" "net/url" "strings" @@ -12,77 +13,110 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" obsv1alpha1 "github.com/rhobs/observability-operator/pkg/apis/observability/v1alpha1" - uiv1alpha1 "github.com/rhobs/observability-operator/pkg/apis/uiplugin/v1alpha1" ) const ( tenantName = "application" tenantID = "1610b0c3-c509-4592-a256-a1871353dbfb" + + tempoStackComponent = "../components/stores/tempostack/resources" + consoleComponent = "../components/console/resources" + + tempoStackBaseName = "tempostack" ) -func tempoStack(instance *obsv1alpha1.ObservabilityInstaller) *tempov1alpha1.TempoStack { - var storageType tempov1alpha1.ObjectStorageSecretType - if oss := instance.Spec.GetCapabilities().GetTracing().GetStorage().GetObjectStorageSpec(); oss != nil { - storageType = toTempoStorageType(oss) +func addTempoStack(overlay *Overlay, instance *obsv1alpha1.ObservabilityInstaller) error { + overlay.AddComponent(tempoStackComponent) + + patch := tempoStackPatch(instance) + patchYAML, err := marshalYAML(patch) + if err != nil { + return fmt.Errorf("marshaling TempoStack patch: %w", err) + } + overlay.AddPatch("patches/tempostack.yaml", patchYAML) + return nil +} + +func addUIPlugin(overlay *Overlay) { + overlay.AddComponent(consoleComponent) +} + +func addTempoSecrets(ctx context.Context, overlay *Overlay, k8sClient client.Client, k8sReader client.Reader, instance *obsv1alpha1.ObservabilityInstaller) error { + secrets, err := tempoStackSecrets(ctx, k8sClient, k8sReader, *instance) + if err != nil { + return err + } + + if secrets.objectStorage != nil { + yaml, err := marshalYAML(secrets.objectStorage) + if err != nil { + return fmt.Errorf("marshaling tempo secret: %w", err) + } + overlay.AddResource("resources/tempo-secret.yaml", yaml) + } + if secrets.objectStorageTLSSecret != nil { + yaml, err := marshalYAML(secrets.objectStorageTLSSecret) + if err != nil { + return fmt.Errorf("marshaling tempo TLS secret: %w", err) + } + overlay.AddResource("resources/tempo-tls-secret.yaml", yaml) + } + if secrets.objectStorageCAConfigMap != nil { + yaml, err := marshalYAML(secrets.objectStorageCAConfigMap) + if err != nil { + return fmt.Errorf("marshaling tempo CA configmap: %w", err) + } + overlay.AddResource("resources/tempo-ca-configmap.yaml", yaml) } - credentialMode := toTempoCredentialMode(instance.Spec.GetCapabilities().GetTracing().GetStorage().GetObjectStorageSpec()) - tempo := &tempov1alpha1.TempoStack{ + return nil +} + +// tempoStackPatch returns a strategic merge patch for the base TempoStack manifest. +// It sets only dynamic fields; hard-coded values are in the base manifest. +func tempoStackPatch(instance *obsv1alpha1.ObservabilityInstaller) *tempov1alpha1.TempoStack { + patch := &tempov1alpha1.TempoStack{ TypeMeta: metav1.TypeMeta{ Kind: "TempoStack", APIVersion: tempov1alpha1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ - Name: tempoName(instance.Name), - Namespace: instance.Namespace, + Name: tempoStackBaseName, }, Spec: tempov1alpha1.TempoStackSpec{ Storage: tempov1alpha1.ObjectStorageSpec{ Secret: tempov1alpha1.ObjectStorageSecretSpec{ - Type: storageType, - CredentialMode: credentialMode, - Name: tempoSecretName(instance.Name), - }, - }, - Template: tempov1alpha1.TempoTemplateSpec{ - Gateway: tempov1alpha1.TempoGatewaySpec{ - Enabled: true, - }, - }, - Tenants: &tempov1alpha1.TenantsSpec{ - Mode: tempov1alpha1.ModeOpenShift, - Authentication: []tempov1alpha1.AuthenticationSpec{ - { - TenantName: tenantName, - TenantID: tenantID, - }, + Name: tempoSecretName(instance.Name), }, }, }, } - if storageSpec := instance.Spec.GetCapabilities().GetTracing().GetStorage().GetObjectStorageSpec(); storageSpec != nil { - tls := storageSpec.GetTLS() - enableTLS := tls != nil || s3hasHTTPSEndpoint(*storageSpec) + if oss := instance.Spec.GetCapabilities().GetTracing().GetStorage().GetObjectStorageSpec(); oss != nil { + patch.Spec.Storage.Secret.Type = toTempoStorageType(oss) + patch.Spec.Storage.Secret.CredentialMode = toTempoCredentialMode(oss) + + tls := oss.GetTLS() + enableTLS := tls != nil || s3hasHTTPSEndpoint(*oss) if enableTLS { - tempo.Spec.Storage.TLS = tempov1alpha1.TLSSpec{ + patch.Spec.Storage.TLS = tempov1alpha1.TLSSpec{ Enabled: true, } if tls != nil { if tls.CAConfigMap != nil { - tempo.Spec.Storage.TLS.CA = tempoStorageCAConfigMapName(instance.Name) + patch.Spec.Storage.TLS.CA = tempoStorageCAConfigMapName(instance.Name) } if tls.CertSecret != nil { - tempo.Spec.Storage.TLS.Cert = tempoStorageSecretName(instance.Name) + patch.Spec.Storage.TLS.Cert = tempoStorageSecretName(instance.Name) } if tls.MinVersion != "" { - tempo.Spec.Storage.TLS.MinVersion = tls.MinVersion + patch.Spec.Storage.TLS.MinVersion = tls.MinVersion } } } } - return tempo + return patch } func tempoName(instance string) string { @@ -93,12 +127,10 @@ func tempoStorageCAConfigMapName(name string) string { return fmt.Sprintf("coo-%s-tempo-storage-ca", name) } -// tempoStorageSecretName returns the name of the secret that contains the TLS cert and key for the object storage. func tempoStorageSecretName(name string) string { return fmt.Sprintf("coo-%s-tempo-storage-cert", name) } -// tempoSecretName returns the name of the secret that contains the credentials for the object storage. func tempoSecretName(name string) string { return fmt.Sprintf("coo-%s-tempo", name) } @@ -116,8 +148,7 @@ func s3hasHTTPSEndpoint(storageSpec obsv1alpha1.TracingObjectStorageSpec) bool { } type tempoSecrets struct { - objectStorage *corev1.Secret - + objectStorage *corev1.Secret objectStorageTLSSecret *corev1.Secret objectStorageCAConfigMap *corev1.ConfigMap } @@ -185,7 +216,6 @@ func tempoStackSecrets(ctx context.Context, k8sClient client.Client, k8sReader c return nil, fmt.Errorf("failed to get object storage cert secret %s: %w", tlsSpec.KeySecret.Name, err) } - // Set only if the cert was found, which initialized the secret if objectStorageTLSSecret != nil { objectStorageTLSSecret.Data["tls.key"] = certSecret.Data[tlsSpec.KeySecret.Key] } @@ -300,21 +330,6 @@ func tempoStackSecrets(ctx context.Context, k8sClient client.Client, k8sReader c }, nil } -func uiPlugin() *uiv1alpha1.UIPlugin { - return &uiv1alpha1.UIPlugin{ - TypeMeta: metav1.TypeMeta{ - Kind: "UIPlugin", - APIVersion: uiv1alpha1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "distributed-tracing", - }, - Spec: uiv1alpha1.UIPluginSpec{ - Type: uiv1alpha1.TypeDistributedTracing, - }, - } -} - func toTempoStorageType(objStorage *obsv1alpha1.TracingObjectStorageSpec) tempov1alpha1.ObjectStorageSecretType { if objStorage == nil { return "" @@ -343,3 +358,12 @@ func toTempoCredentialMode(objStorage *obsv1alpha1.TracingObjectStorageSpec) tem return "" } + +// marshalYAML marshals a Kubernetes object to YAML via JSON tags. +func marshalYAML(obj interface{}) ([]byte, error) { + data, err := json.Marshal(obj) + if err != nil { + return nil, err + } + return jsonToYAML(data) +} diff --git a/stack/README.md b/stack/README.md new file mode 100644 index 000000000..18be3768f --- /dev/null +++ b/stack/README.md @@ -0,0 +1,94 @@ +# Declarative kustomize manifests that deploy the observability stack. + +The Go controller in `pkg/controllers/observability/` builds a kustomize overlay +at runtime, using these manifests as base components and applying patches for +dynamic values (storage config, TLS, secrets). See [Generated overlay](#generated-overlay). + +## Why declarative resources instead of programmed controller structs? + +- Kustomize resources can be applied direct by `kubectl` without using the COO. Examples: + - Generate once, apply many times in a multi-cluster. + - Apply to constrained edge nodes that don't run COO. + - One-time install wizards, assisted installers that don't use COO. +- Other teams can contribute resource edits more easily that controller code edits. +- Users can create their own modified versions of the stack and deploy with COO. + +## Directory layout + +``` +stack/ +├── base/ # Shared base: target namespace +├── components/ +│ ├── collectors/ +│ │ ├── logging/ # ClusterLogForwarder + Cluster Logging operator +│ │ ├── network/ # FlowCollector + Network Observability operator +│ │ └── tracing/ # OpenTelemetryCollector + RBAC + Red Hat build of OpenTelemetry operator +│ ├── stores/ +│ │ ├── lokistack/ # LokiStack + Loki operator +│ │ └── tempostack/ # TempoStack + RBAC + Tempo operator +│ ├── console/ # UIPlugin (OpenShift console plugins) +│ ├── korrel8r/ # Korrel8r correlation engine +│ └── s3-storage/ # S3 object storage (minio, ODF, or local) +├── overlays/ +│ ├── single-cluster/ # All collectors + stores + minio on one cluster +│ ├── hub/ # Stores only (receives signals from edge clusters) +│ └── edge/ # Collectors only (forwards signals to a hub) +``` + +Each component has two sub-directories: + +- `operator/` (optional) — Namespace, OperatorGroup, and Subscription to install the operator via OLM. +- `resources/` — Operand CRs and supporting resources (RBAC, secrets, configmaps). + +Overlays compose components and apply namespace transformers and patches. + +## Generated overlay + +The Go controller builds an in-memory kustomize overlay using +`sigs.k8s.io/kustomize/api/krusty`. The key files: + +- `stack/fs.go` — embeds `base/` and `components/` into the binary via `//go:embed`. +- `pkg/controllers/observability/overlay.go` — `Overlay` type that populates an + in-memory `filesys.FileSystem` with the embedded manifests plus generated patches + and resources, then runs `krusty.MakeKustomizer().Run()` to produce `[]client.Object`. +- `pkg/controllers/observability/*_components.go` — refactored to add patches to an overlay, + then generate objects, rather than constructing objects directly. + +The generated overlay is equivalent to: + +``` +generated/ +├── kustomization.yaml # components + patches + resources +├── namespace-transformer.yaml # sets namespace from instance +├── patches/ +│ └── tempostack.yaml # dynamic storage config (type, credentials, TLS) +└── resources/ + ├── tempo-secret.yaml # assembled storage credentials + ├── tempo-tls-secret.yaml # TLS cert (conditional) + └── tempo-ca-configmap.yaml # CA bundle (conditional) +``` + +Hard-coded values (tenants, gateway, query frontend) live in the base component manifests. +The overlay patches only dynamic fields derived from the `ObservabilityInstaller` spec. + +### Status + +- **Done**: TempoStack, storage secrets, UIPlugin (via overlay) +- **Not yet converted**: OpenTelemetryCollector, OTEL RBAC (still built as Go objects) +- **Not yet converted**: Operator Subscriptions (still built as Go objects) + +## To be done + +- Convert OpenTelemetryCollector and its RBAC to the overlay approach + (currently still built as Go objects in `otel_components.go`). +- Convert operator Subscriptions to the overlay approach. +- For standalone (non-controller) use, add example storage secrets or a + documented manual step for providing S3/Azure/GCS credentials. +- LokiStack and logging/network components have not been compared against Go code. + +## Open questions + +- The Go controller installs operators via `Subscription` objects it constructs + at runtime (with version info from `Options`). The manifest `operator/` + directories hardcode channel/source. How should operator versions be managed? +- tempostack.yaml has hard coded tenant IDs, this looks incorrect. diff --git a/stack/base/kustomization.yaml b/stack/base/kustomization.yaml new file mode 100644 index 000000000..48ef36e57 --- /dev/null +++ b/stack/base/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - namespace.yaml diff --git a/stack/base/namespace.yaml b/stack/base/namespace.yaml new file mode 100644 index 000000000..f60f27900 --- /dev/null +++ b/stack/base/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-cluster-observability-operator diff --git a/stack/components/collectors/logging/operator/kustomization.yaml b/stack/components/collectors/logging/operator/kustomization.yaml new file mode 100644 index 000000000..bdfb262da --- /dev/null +++ b/stack/components/collectors/logging/operator/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - namespace.yaml + - operatorgroup.yaml + - subscription.yaml diff --git a/stack/components/collectors/logging/operator/namespace.yaml b/stack/components/collectors/logging/operator/namespace.yaml new file mode 100644 index 000000000..2d1cfd07d --- /dev/null +++ b/stack/components/collectors/logging/operator/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + openshift.io/cluster-monitoring: "true" + name: openshift-logging diff --git a/stack/components/collectors/logging/operator/operatorgroup.yaml b/stack/components/collectors/logging/operator/operatorgroup.yaml new file mode 100644 index 000000000..abb87ca12 --- /dev/null +++ b/stack/components/collectors/logging/operator/operatorgroup.yaml @@ -0,0 +1,9 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + annotations: + olm.providedAPIs: ClusterLogForwarder.v1.observability.openshift.io + name: openshift-logging + namespace: openshift-logging +spec: + upgradeStrategy: Default diff --git a/stack/components/collectors/logging/operator/subscription.yaml b/stack/components/collectors/logging/operator/subscription.yaml new file mode 100644 index 000000000..ccf07b2ed --- /dev/null +++ b/stack/components/collectors/logging/operator/subscription.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: cluster-logging + namespace: openshift-logging +spec: + channel: stable-6.5 + name: cluster-logging + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/stack/components/collectors/logging/resources/clusterlogforwarder.yaml b/stack/components/collectors/logging/resources/clusterlogforwarder.yaml new file mode 100644 index 000000000..8004511d6 --- /dev/null +++ b/stack/components/collectors/logging/resources/clusterlogforwarder.yaml @@ -0,0 +1,28 @@ +apiVersion: observability.openshift.io/v1 +kind: ClusterLogForwarder +metadata: + name: collector + namespace: openshift-logging +spec: + serviceAccount: + name: collector + outputs: + - name: lokistack + type: lokiStack + lokiStack: + target: + name: lokistack + authentication: + token: + from: serviceAccount + tls: + ca: + key: service-ca.crt + configMapName: openshift-service-ca.crt + pipelines: + - name: default + inputRefs: + - application + - infrastructure + outputRefs: + - lokistack diff --git a/stack/components/collectors/logging/resources/kustomization.yaml b/stack/components/collectors/logging/resources/kustomization.yaml new file mode 100644 index 000000000..a413ba000 --- /dev/null +++ b/stack/components/collectors/logging/resources/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - serviceaccount.yaml + - clusterlogforwarder.yaml diff --git a/stack/components/collectors/logging/resources/serviceaccount.yaml b/stack/components/collectors/logging/resources/serviceaccount.yaml new file mode 100644 index 000000000..553675215 --- /dev/null +++ b/stack/components/collectors/logging/resources/serviceaccount.yaml @@ -0,0 +1,73 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: collector + namespace: openshift-logging +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: logging-collector-logs-writer +rules: + - apiGroups: + - loki.grafana.com + resourceNames: + - logs + resources: + - application + - audit + - infrastructure + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: collect-logs-writer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: logging-collector-logs-writer +subjects: + - kind: ServiceAccount + name: collector + namespace: openshift-logging +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: collect-application-logs +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: collect-application-logs +subjects: + - kind: ServiceAccount + name: collector + namespace: openshift-logging +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: collect-infrastructure-logs +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: collect-infrastructure-logs +subjects: + - kind: ServiceAccount + name: collector + namespace: openshift-logging +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: collect-audit-logs +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: collect-audit-logs +subjects: + - kind: ServiceAccount + name: collector + namespace: openshift-logging diff --git a/stack/components/collectors/network/operator/kustomization.yaml b/stack/components/collectors/network/operator/kustomization.yaml new file mode 100644 index 000000000..bdfb262da --- /dev/null +++ b/stack/components/collectors/network/operator/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - namespace.yaml + - operatorgroup.yaml + - subscription.yaml diff --git a/stack/components/collectors/network/operator/namespace.yaml b/stack/components/collectors/network/operator/namespace.yaml new file mode 100644 index 000000000..e9214da52 --- /dev/null +++ b/stack/components/collectors/network/operator/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + openshift.io/cluster-monitoring: "true" + name: openshift-netobserv-operator diff --git a/stack/components/collectors/network/operator/operatorgroup.yaml b/stack/components/collectors/network/operator/operatorgroup.yaml new file mode 100644 index 000000000..0dfd1a24d --- /dev/null +++ b/stack/components/collectors/network/operator/operatorgroup.yaml @@ -0,0 +1,9 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + annotations: + olm.providedAPIs: "FlowCollector.v1alpha1.flows.netobserv.io,FlowCollector.v1beta1.flows.netobserv.io,FlowCollector.v1beta2.flows.netobserv.io,FlowMetric.v1alpha1.flows.netobserv.io" + name: openshift-netobserv-operator + namespace: openshift-netobserv-operator +spec: + upgradeStrategy: Default diff --git a/stack/components/collectors/network/operator/subscription.yaml b/stack/components/collectors/network/operator/subscription.yaml new file mode 100644 index 000000000..240fa1182 --- /dev/null +++ b/stack/components/collectors/network/operator/subscription.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: netobserv-operator + namespace: openshift-netobserv-operator +spec: + channel: stable + name: netobserv-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/stack/components/collectors/network/resources/flowcollector.yaml b/stack/components/collectors/network/resources/flowcollector.yaml new file mode 100644 index 000000000..9e88e05e2 --- /dev/null +++ b/stack/components/collectors/network/resources/flowcollector.yaml @@ -0,0 +1,67 @@ +apiVersion: flows.netobserv.io/v1beta2 +kind: FlowCollector +metadata: + name: cluster +spec: + namespace: netobserv + deploymentModel: Direct + agent: + type: eBPF + ebpf: + cacheActiveTimeout: 5s + cacheMaxFlows: 100000 + excludeInterfaces: + - lo + kafkaBatchSize: 1048576 + logLevel: info + sampling: 50 + consolePlugin: + autoscaler: + maxReplicas: 3 + status: Disabled + enable: true + imagePullPolicy: IfNotPresent + logLevel: info + portNaming: + enable: true + quickFilters: + - default: true + filter: + flow_layer: app + name: Applications + - filter: + flow_layer: infra + name: Infrastructure + - default: true + filter: + dst_kind: Pod + src_kind: Pod + name: Pods network + - filter: + dst_kind: Service + name: Services network + replicas: 1 + loki: + enable: true + mode: LokiStack + lokiStack: + name: lokistack + readTimeout: 30s + writeBatchSize: 102400 + writeBatchWait: 1s + writeTimeout: 10s + processor: + imagePullPolicy: IfNotPresent + kafkaConsumerAutoscaler: + maxReplicas: 3 + status: Disabled + kafkaConsumerBatchSize: 10485760 + kafkaConsumerQueueCapacity: 1000 + kafkaConsumerReplicas: 3 + logLevel: info + logTypes: Flows + metrics: + server: + port: 9102 + tls: + type: Disabled diff --git a/stack/components/collectors/network/resources/kustomization.yaml b/stack/components/collectors/network/resources/kustomization.yaml new file mode 100644 index 000000000..975aad1f8 --- /dev/null +++ b/stack/components/collectors/network/resources/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - flowcollector.yaml diff --git a/stack/components/collectors/tracing/operator/kustomization.yaml b/stack/components/collectors/tracing/operator/kustomization.yaml new file mode 100644 index 000000000..bdfb262da --- /dev/null +++ b/stack/components/collectors/tracing/operator/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - namespace.yaml + - operatorgroup.yaml + - subscription.yaml diff --git a/stack/components/collectors/tracing/operator/namespace.yaml b/stack/components/collectors/tracing/operator/namespace.yaml new file mode 100644 index 000000000..92b45a727 --- /dev/null +++ b/stack/components/collectors/tracing/operator/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: project.openshift.io/v1 +kind: Namespace +metadata: + name: openshift-opentelemetry-operator diff --git a/stack/components/collectors/tracing/operator/operatorgroup.yaml b/stack/components/collectors/tracing/operator/operatorgroup.yaml new file mode 100644 index 000000000..5ee5b4902 --- /dev/null +++ b/stack/components/collectors/tracing/operator/operatorgroup.yaml @@ -0,0 +1,7 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: openshift-opentelemetry-operator + namespace: openshift-opentelemetry-operator +spec: + upgradeStrategy: Default diff --git a/stack/components/collectors/tracing/operator/subscription.yaml b/stack/components/collectors/tracing/operator/subscription.yaml new file mode 100644 index 000000000..0a9e2ffcc --- /dev/null +++ b/stack/components/collectors/tracing/operator/subscription.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: opentelemetry-product + namespace: openshift-opentelemetry-operator +spec: + channel: stable + name: opentelemetry-product + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/stack/components/collectors/tracing/resources/kustomization.yaml b/stack/components/collectors/tracing/resources/kustomization.yaml new file mode 100644 index 000000000..5312b2aeb --- /dev/null +++ b/stack/components/collectors/tracing/resources/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - rbac.yaml + - opentelemetrycollector.yaml diff --git a/stack/components/collectors/tracing/resources/opentelemetrycollector.yaml b/stack/components/collectors/tracing/resources/opentelemetrycollector.yaml new file mode 100644 index 000000000..a51efb98f --- /dev/null +++ b/stack/components/collectors/tracing/resources/opentelemetrycollector.yaml @@ -0,0 +1,66 @@ +apiVersion: opentelemetry.io/v1beta1 +kind: OpenTelemetryCollector +metadata: + name: cluster-collector +spec: + mode: deployment + upgradeStrategy: automatic + config: + extensions: + bearertokenauth: + filename: /var/run/secrets/kubernetes.io/serviceaccount/token + + receivers: + otlp: + protocols: + grpc: {} + http: {} + jaeger: + protocols: + grpc: {} + thrift_http: {} + thrift_compact: {} + thrift_binary: {} + zipkin: {} + + processors: + k8sattributes: {} + batch: {} + memory_limiter: + check_interval: 1s + limit_percentage: 75 + spike_limit_percentage: 25 + + exporters: + debug: {} + otlphttp/tempo: + endpoint: https://tempo-tempostack-gateway.openshift-cluster-observability-operator.svc.cluster.local:8080/api/traces/v1/application + tls: + insecure: false + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt + reload_interval: 5s + auth: + authenticator: bearertokenauth + + service: + telemetry: + logs: + level: "INFO" + development: true + encoding: "json" + metrics: + level: detailed + readers: + - pull: + exporter: + prometheus: + host: '0.0.0.0' + port: 8888 + extensions: [bearertokenauth] + pipelines: + traces: + receivers: [otlp, jaeger, zipkin] + processors: [memory_limiter, k8sattributes, batch] + exporters: + - debug + - otlphttp/tempo diff --git a/stack/components/collectors/tracing/resources/rbac.yaml b/stack/components/collectors/tracing/resources/rbac.yaml new file mode 100644 index 000000000..84ac8397b --- /dev/null +++ b/stack/components/collectors/tracing/resources/rbac.yaml @@ -0,0 +1,45 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: otel-collector-k8sattributes +rules: + - apiGroups: [""] + resources: ["pods", "namespaces", "nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: otel-collector-k8sattributes +roleRef: + kind: ClusterRole + name: otel-collector-k8sattributes + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: cluster-collector-collector +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: traces-writer-application +rules: + - apiGroups: [tempo.grafana.com] + resources: [application] + resourceNames: [traces] + verbs: [create] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: traces-writer-application +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: traces-writer-application +subjects: + - kind: ServiceAccount + name: cluster-collector-collector diff --git a/stack/components/console/resources/kustomization.yaml b/stack/components/console/resources/kustomization.yaml new file mode 100644 index 000000000..25c209e2e --- /dev/null +++ b/stack/components/console/resources/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - uiplugin.yaml diff --git a/stack/components/console/resources/uiplugin.yaml b/stack/components/console/resources/uiplugin.yaml new file mode 100644 index 000000000..37f065b32 --- /dev/null +++ b/stack/components/console/resources/uiplugin.yaml @@ -0,0 +1,6 @@ +apiVersion: observability.openshift.io/v1alpha1 +kind: UIPlugin +metadata: + name: distributed-tracing +spec: + type: DistributedTracing diff --git a/stack/components/korrel8r/resources/configmap.yaml b/stack/components/korrel8r/resources/configmap.yaml new file mode 100644 index 000000000..df1c8dadb --- /dev/null +++ b/stack/components/korrel8r/resources/configmap.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: korrel8r-config +data: + korrel8r.yaml: | + rules: + - name: LogToTrace + stores: + - domain: log + config: + lokistack: https://lokistack-gateway-http.openshift-cluster-observability-operator.svc:8080 + - domain: trace + config: + tempostack: https://tempo-tempostack-gateway.openshift-cluster-observability-operator.svc:8080 diff --git a/stack/components/korrel8r/resources/korrel8r.yaml b/stack/components/korrel8r/resources/korrel8r.yaml new file mode 100644 index 000000000..f21982939 --- /dev/null +++ b/stack/components/korrel8r/resources/korrel8r.yaml @@ -0,0 +1,7 @@ +apiVersion: korrel8r.openshift.io/v1alpha1 +kind: Korrel8r +metadata: + name: korrel8r +spec: + configMap: + name: korrel8r-config diff --git a/stack/components/korrel8r/resources/kustomization.yaml b/stack/components/korrel8r/resources/kustomization.yaml new file mode 100644 index 000000000..a5d4e966a --- /dev/null +++ b/stack/components/korrel8r/resources/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - korrel8r.yaml + - configmap.yaml diff --git a/stack/components/s3-storage/local/kustomization.yaml b/stack/components/s3-storage/local/kustomization.yaml new file mode 100644 index 000000000..e888833b1 --- /dev/null +++ b/stack/components/s3-storage/local/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - storage.yaml diff --git a/stack/components/s3-storage/local/storage.yaml b/stack/components/s3-storage/local/storage.yaml new file mode 100644 index 000000000..0156ba396 --- /dev/null +++ b/stack/components/s3-storage/local/storage.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: lokistack-storage +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: tempostack-storage +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/stack/components/s3-storage/minio/kustomization.yaml b/stack/components/s3-storage/minio/kustomization.yaml new file mode 100644 index 000000000..e94a99d5e --- /dev/null +++ b/stack/components/s3-storage/minio/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - minio.yaml + - secrets.yaml diff --git a/stack/components/s3-storage/minio/minio.yaml b/stack/components/s3-storage/minio/minio.yaml new file mode 100644 index 000000000..b71041d1d --- /dev/null +++ b/stack/components/s3-storage/minio/minio.yaml @@ -0,0 +1,66 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: minio + name: minio +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: minio + name: minio +spec: + selector: + matchLabels: + app.kubernetes.io/name: minio + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/name: minio + spec: + containers: + - name: minio + image: quay.io/minio/minio + command: + - /bin/sh + - -c + - | + mkdir -p /storage/loki /storage/tempo && \ + minio server /storage + env: + - name: MINIO_ACCESS_KEY + value: minio + - name: MINIO_SECRET_KEY + value: minio123 + ports: + - containerPort: 9000 + volumeMounts: + - name: storage + mountPath: /storage + volumes: + - name: storage + persistentVolumeClaim: + claimName: minio +--- +apiVersion: v1 +kind: Service +metadata: + name: minio +spec: + selector: + app.kubernetes.io/name: minio + ports: + - port: 9000 + protocol: TCP + targetPort: 9000 + type: ClusterIP diff --git a/stack/components/s3-storage/minio/secrets.yaml b/stack/components/s3-storage/minio/secrets.yaml new file mode 100644 index 000000000..324793c55 --- /dev/null +++ b/stack/components/s3-storage/minio/secrets.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Secret +metadata: + name: lokistack-s3 +stringData: + endpoint: http://minio.openshift-cluster-observability-operator.svc:9000 + bucketnames: loki + access_key_id: minio + access_key_secret: minio123 +--- +apiVersion: v1 +kind: Secret +metadata: + name: tempostack-s3 +stringData: + endpoint: http://minio.openshift-cluster-observability-operator.svc:9000 + bucket: tempo + access_key_id: minio + access_key_secret: minio123 diff --git a/stack/components/s3-storage/odf/kustomization.yaml b/stack/components/s3-storage/odf/kustomization.yaml new file mode 100644 index 000000000..26a83a106 --- /dev/null +++ b/stack/components/s3-storage/odf/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - objectbucketclaims.yaml diff --git a/stack/components/s3-storage/odf/objectbucketclaims.yaml b/stack/components/s3-storage/odf/objectbucketclaims.yaml new file mode 100644 index 000000000..dc8cd0089 --- /dev/null +++ b/stack/components/s3-storage/odf/objectbucketclaims.yaml @@ -0,0 +1,15 @@ +apiVersion: objectbucket.io/v1alpha1 +kind: ObjectBucketClaim +metadata: + name: lokistack-s3 +spec: + generateBucketName: loki + storageClassName: openshift-storage.noobaa.io +--- +apiVersion: objectbucket.io/v1alpha1 +kind: ObjectBucketClaim +metadata: + name: tempostack-s3 +spec: + generateBucketName: tempo + storageClassName: openshift-storage.noobaa.io diff --git a/stack/components/stores/lokistack/operator/kustomization.yaml b/stack/components/stores/lokistack/operator/kustomization.yaml new file mode 100644 index 000000000..bdfb262da --- /dev/null +++ b/stack/components/stores/lokistack/operator/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - namespace.yaml + - operatorgroup.yaml + - subscription.yaml diff --git a/stack/components/stores/lokistack/operator/namespace.yaml b/stack/components/stores/lokistack/operator/namespace.yaml new file mode 100644 index 000000000..41501f277 --- /dev/null +++ b/stack/components/stores/lokistack/operator/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + openshift.io/cluster-monitoring: "true" + name: openshift-operators-redhat diff --git a/stack/components/stores/lokistack/operator/operatorgroup.yaml b/stack/components/stores/lokistack/operator/operatorgroup.yaml new file mode 100644 index 000000000..76bdb3f7d --- /dev/null +++ b/stack/components/stores/lokistack/operator/operatorgroup.yaml @@ -0,0 +1,9 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + annotations: + olm.providedAPIs: AlertingRule.v1.loki.grafana.com,LokiStack.v1.loki.grafana.com,RecordingRule.v1.loki.grafana.com,RulerConfig.v1.loki.grafana.com + name: openshift-operators-redhat + namespace: openshift-operators-redhat +spec: + upgradeStrategy: Default diff --git a/stack/components/stores/lokistack/operator/subscription.yaml b/stack/components/stores/lokistack/operator/subscription.yaml new file mode 100644 index 000000000..dd2d45e49 --- /dev/null +++ b/stack/components/stores/lokistack/operator/subscription.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: loki-operator + namespace: openshift-operators-redhat +spec: + channel: stable-6.5 + name: loki-operator + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/stack/components/stores/lokistack/resources/kustomization.yaml b/stack/components/stores/lokistack/resources/kustomization.yaml new file mode 100644 index 000000000..9eaeafdaa --- /dev/null +++ b/stack/components/stores/lokistack/resources/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - lokistack.yaml diff --git a/stack/components/stores/lokistack/resources/lokistack.yaml b/stack/components/stores/lokistack/resources/lokistack.yaml new file mode 100644 index 000000000..26ded0c09 --- /dev/null +++ b/stack/components/stores/lokistack/resources/lokistack.yaml @@ -0,0 +1,23 @@ +apiVersion: loki.grafana.com/v1 +kind: LokiStack +metadata: + name: lokistack +spec: + size: 1x.demo + storage: + schemas: + - version: v13 + effectiveDate: "2024-10-01" + secret: + name: lokistack-s3 + type: s3 + tenants: + mode: openshift-logging + rules: + enabled: true + selector: + matchLabels: + openshift.io/log-alerting: "true" + namespaceSelector: + matchLabels: + openshift.io/log-alerting: "true" diff --git a/stack/components/stores/tempostack/operator/kustomization.yaml b/stack/components/stores/tempostack/operator/kustomization.yaml new file mode 100644 index 000000000..bdfb262da --- /dev/null +++ b/stack/components/stores/tempostack/operator/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - namespace.yaml + - operatorgroup.yaml + - subscription.yaml diff --git a/stack/components/stores/tempostack/operator/namespace.yaml b/stack/components/stores/tempostack/operator/namespace.yaml new file mode 100644 index 000000000..461dbcdf8 --- /dev/null +++ b/stack/components/stores/tempostack/operator/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: project.openshift.io/v1 +kind: Namespace +metadata: + name: openshift-tempo-operator diff --git a/stack/components/stores/tempostack/operator/operatorgroup.yaml b/stack/components/stores/tempostack/operator/operatorgroup.yaml new file mode 100644 index 000000000..7cebd1232 --- /dev/null +++ b/stack/components/stores/tempostack/operator/operatorgroup.yaml @@ -0,0 +1,7 @@ +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: openshift-tempo-operator + namespace: openshift-tempo-operator +spec: + upgradeStrategy: Default diff --git a/stack/components/stores/tempostack/operator/subscription.yaml b/stack/components/stores/tempostack/operator/subscription.yaml new file mode 100644 index 000000000..d8cb5761e --- /dev/null +++ b/stack/components/stores/tempostack/operator/subscription.yaml @@ -0,0 +1,10 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: tempo-product + namespace: openshift-tempo-operator +spec: + channel: stable + name: tempo-product + source: redhat-operators + sourceNamespace: openshift-marketplace diff --git a/stack/components/stores/tempostack/resources/kustomization.yaml b/stack/components/stores/tempostack/resources/kustomization.yaml new file mode 100644 index 000000000..cc4bf4adc --- /dev/null +++ b/stack/components/stores/tempostack/resources/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - tempostack.yaml + - rbac.yaml diff --git a/stack/components/stores/tempostack/resources/rbac.yaml b/stack/components/stores/tempostack/resources/rbac.yaml new file mode 100644 index 000000000..ac9459c1c --- /dev/null +++ b/stack/components/stores/tempostack/resources/rbac.yaml @@ -0,0 +1,22 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: traces-reader-application +rules: + - apiGroups: [tempo.grafana.com] + resources: [application] + resourceNames: [traces] + verbs: [get] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: traces-reader-application +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: traces-reader-application +subjects: + - kind: Group + apiGroup: rbac.authorization.k8s.io + name: system:authenticated \ No newline at end of file diff --git a/stack/components/stores/tempostack/resources/tempostack.yaml b/stack/components/stores/tempostack/resources/tempostack.yaml new file mode 100644 index 000000000..15db1a922 --- /dev/null +++ b/stack/components/stores/tempostack/resources/tempostack.yaml @@ -0,0 +1,20 @@ +apiVersion: tempo.grafana.com/v1alpha1 +kind: TempoStack +metadata: + name: tempostack +spec: + managementState: Managed + storage: + secret: {} + storageSize: 1Gi + tenants: + mode: openshift + authentication: + - tenantName: application + tenantId: 1610b0c3-c509-4592-a256-a1871353dbfb + template: + gateway: + enabled: true + queryFrontend: + jaegerQuery: + enabled: true diff --git a/stack/fs.go b/stack/fs.go new file mode 100644 index 000000000..b5ddedb52 --- /dev/null +++ b/stack/fs.go @@ -0,0 +1,6 @@ +package stack + +import "embed" + +//go:embed base components +var FS embed.FS diff --git a/stack/overlays/edge/kustomization.yaml b/stack/overlays/edge/kustomization.yaml new file mode 100644 index 000000000..97b3a213d --- /dev/null +++ b/stack/overlays/edge/kustomization.yaml @@ -0,0 +1,20 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +transformers: + - namespace-transformer.yaml + +components: + # Collectors only — forward signals to a hub cluster + - ../../components/collectors/tracing/operator + - ../../components/collectors/tracing/resources + - ../../components/collectors/logging/operator + - ../../components/collectors/logging/resources + - ../../components/collectors/network/operator + - ../../components/collectors/network/resources + +patches: + - path: patches/forward-to-hub.yaml diff --git a/stack/overlays/edge/namespace-transformer.yaml b/stack/overlays/edge/namespace-transformer.yaml new file mode 100644 index 000000000..f3a2ca94b --- /dev/null +++ b/stack/overlays/edge/namespace-transformer.yaml @@ -0,0 +1,7 @@ +apiVersion: builtin +kind: NamespaceTransformer +metadata: + name: namespace-transformer +namespace: openshift-cluster-observability-operator +unsetOnly: true +setRoleBindingSubjects: allServiceAccounts diff --git a/stack/overlays/edge/patches/forward-to-hub.yaml b/stack/overlays/edge/patches/forward-to-hub.yaml new file mode 100644 index 000000000..c1f43c0ea --- /dev/null +++ b/stack/overlays/edge/patches/forward-to-hub.yaml @@ -0,0 +1,17 @@ +apiVersion: opentelemetry.io/v1beta1 +kind: OpenTelemetryCollector +metadata: + name: cluster-collector +spec: + config: + exporters: + otlp: + # Override to point at the hub cluster's ingress + endpoint: hub-cluster-otel-ingress.example.com:443 + tls: + insecure: false + service: + pipelines: + traces: + receivers: [otlp] + exporters: [otlp] diff --git a/stack/overlays/hub/kustomization.yaml b/stack/overlays/hub/kustomization.yaml new file mode 100644 index 000000000..034c70b83 --- /dev/null +++ b/stack/overlays/hub/kustomization.yaml @@ -0,0 +1,23 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +transformers: + - namespace-transformer.yaml + +components: + # Stores — receive signals from edge clusters + - ../../components/stores/lokistack/operator + - ../../components/stores/lokistack/resources + - ../../components/stores/tempostack/operator + - ../../components/stores/tempostack/resources + # Console + - ../../components/console/resources + # Shared + - ../../components/s3-storage/minio + - ../../components/korrel8r/resources + +patches: + - path: patches/korrel8r-config.yaml diff --git a/stack/overlays/hub/namespace-transformer.yaml b/stack/overlays/hub/namespace-transformer.yaml new file mode 100644 index 000000000..f3a2ca94b --- /dev/null +++ b/stack/overlays/hub/namespace-transformer.yaml @@ -0,0 +1,7 @@ +apiVersion: builtin +kind: NamespaceTransformer +metadata: + name: namespace-transformer +namespace: openshift-cluster-observability-operator +unsetOnly: true +setRoleBindingSubjects: allServiceAccounts diff --git a/stack/overlays/hub/patches/korrel8r-config.yaml b/stack/overlays/hub/patches/korrel8r-config.yaml new file mode 100644 index 000000000..df1c8dadb --- /dev/null +++ b/stack/overlays/hub/patches/korrel8r-config.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: korrel8r-config +data: + korrel8r.yaml: | + rules: + - name: LogToTrace + stores: + - domain: log + config: + lokistack: https://lokistack-gateway-http.openshift-cluster-observability-operator.svc:8080 + - domain: trace + config: + tempostack: https://tempo-tempostack-gateway.openshift-cluster-observability-operator.svc:8080 diff --git a/stack/overlays/single-cluster/kustomization.yaml b/stack/overlays/single-cluster/kustomization.yaml new file mode 100644 index 000000000..876d03232 --- /dev/null +++ b/stack/overlays/single-cluster/kustomization.yaml @@ -0,0 +1,30 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../base + +transformers: + - namespace-transformer.yaml + +components: + # Collectors + - ../../components/collectors/tracing/operator + - ../../components/collectors/tracing/resources + - ../../components/collectors/logging/operator + - ../../components/collectors/logging/resources + - ../../components/collectors/network/operator + - ../../components/collectors/network/resources + # Stores + - ../../components/stores/lokistack/operator + - ../../components/stores/lokistack/resources + - ../../components/stores/tempostack/operator + - ../../components/stores/tempostack/resources + # Console + - ../../components/console/resources + # Shared + - ../../components/s3-storage/minio + - ../../components/korrel8r/resources + +patches: + - path: patches/korrel8r-config.yaml diff --git a/stack/overlays/single-cluster/namespace-transformer.yaml b/stack/overlays/single-cluster/namespace-transformer.yaml new file mode 100644 index 000000000..f3a2ca94b --- /dev/null +++ b/stack/overlays/single-cluster/namespace-transformer.yaml @@ -0,0 +1,7 @@ +apiVersion: builtin +kind: NamespaceTransformer +metadata: + name: namespace-transformer +namespace: openshift-cluster-observability-operator +unsetOnly: true +setRoleBindingSubjects: allServiceAccounts diff --git a/stack/overlays/single-cluster/patches/korrel8r-config.yaml b/stack/overlays/single-cluster/patches/korrel8r-config.yaml new file mode 100644 index 000000000..a0a7c1f66 --- /dev/null +++ b/stack/overlays/single-cluster/patches/korrel8r-config.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: korrel8r-config +data: + korrel8r.yaml: | + rules: + - name: LogToTrace + stores: + - domain: log + config: + lokistack: https://lokistack-gateway-http.openshift-cluster-observability-operator.svc:8080 + - domain: trace + config: + tempostack: https://tempo-tempostack-gateway.openshift-cluster-observability-operator.svc:8080 + - domain: netflow + config: + lokistack: https://lokistack-gateway-http.openshift-cluster-observability-operator.svc:8080