├── VERSION ├── .github ├── CODEOWNERS ├── file-filters.yaml ├── workflows │ ├── scripts │ │ ├── increase_version.sh │ │ └── validate_version_increment.sh │ ├── check-pr-title.yml │ ├── trigger-release.yml │ └── discover_new_versions.yaml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── pull_request.md ├── charts └── lumigo-operator │ ├── charts │ └── .gitignore │ ├── Chart.lock │ ├── templates │ ├── service-account.yaml │ ├── metrics-reader-rbac.yaml │ ├── metrics-service.yaml │ ├── telemetry-proxy-service.yaml │ ├── cluster-agent-service.yaml │ ├── proxy-rbac.yaml │ ├── uninstallation │ │ └── uninstall-hook.yaml │ ├── manager-rbac.yaml │ ├── leader-election-rbac.yaml │ ├── installation │ │ └── install-upgrade-hook.yaml │ ├── watchdog-deployment.yaml │ ├── _helpers.tpl │ ├── target-allocator.yaml │ └── NOTES.txt │ ├── samples │ └── operator_v1alpha1_lumigo.yaml │ ├── .helmignore │ └── Chart.yaml ├── kube-rbac-proxy ├── VERSION.kube-rbac-proxy ├── VERSION.base-image └── publish.sh ├── tests ├── quickstart │ ├── resources │ │ ├── .gitignore │ │ └── kind-config.yaml.tpl │ └── internal │ │ ├── load_docker_image.go │ │ ├── context.go │ │ └── build_docker_image.go ├── kubernetes-distros │ ├── kind │ │ ├── resources │ │ │ ├── .gitignore │ │ │ ├── kind-config.yaml.tpl │ │ │ └── otlp-sink │ │ │ │ └── config.yaml.tpl │ │ ├── apps │ │ │ ├── python │ │ │ │ ├── Dockerfile │ │ │ │ └── app.py │ │ │ ├── client │ │ │ │ ├── Dockerfile │ │ │ │ ├── package.json │ │ │ │ ├── app.js │ │ │ │ └── package-lock.json │ │ │ └── server │ │ │ │ ├── Dockerfile │ │ │ │ ├── package.json │ │ │ │ └── app.js │ │ └── internal │ │ │ ├── load_docker_image.go │ │ │ ├── lumigo.go │ │ │ ├── context.go │ │ │ └── build_docker_image.go │ └── amazon-eks │ │ └── cdk │ │ ├── .npmignore │ │ ├── .gitignore │ │ ├── jest.config.js │ │ ├── express │ │ ├── Dockerfile │ │ ├── package.json │ │ └── src │ │ │ └── index.js │ │ ├── package.json │ │ ├── tsconfig.json │ │ ├── bin │ │ └── cdk.ts │ │ ├── README.md │ │ └── cdk.json └── README.md ├── telemetryproxy ├── src │ ├── .gitignore │ ├── README.md │ ├── receiver │ │ ├── k8sobjectsreceiver │ │ │ ├── Makefile │ │ │ ├── testdata │ │ │ │ ├── invalid_config.yaml │ │ │ │ ├── pull_resource_version_config.yaml │ │ │ │ ├── config_watch_resource_version.yaml │ │ │ │ └── config.yaml │ │ │ ├── metadata.yaml │ │ │ ├── doc.go │ │ │ ├── internal │ │ │ │ └── metadata │ │ │ │ │ └── generated_status.go │ │ │ ├── factory.go │ │ │ ├── mock_log_consumer_test.go │ │ │ ├── mock_discovery_client_test.go │ │ │ ├── factory_test.go │ │ │ ├── mock_dynamic_client_test.go │ │ │ └── unstructured_to_logdata.go │ │ └── lumigooperatorheartbeatreceiver │ │ │ ├── config.go │ │ │ ├── README.md │ │ │ ├── factory.go │ │ │ ├── go.mod │ │ │ └── receiver.go │ ├── go.mod │ ├── internal │ │ └── tools │ │ │ ├── empty_test.go │ │ │ ├── go.mod │ │ │ └── tools.go │ ├── processor │ │ └── k8sdataenricherprocessor │ │ │ ├── config.go │ │ │ ├── internal │ │ │ └── relevant_gvk.go │ │ │ └── go.mod │ ├── Makefile │ └── builder │ │ └── config.yaml ├── .gitignore ├── docker │ └── etc │ │ └── common-config.yaml └── Dockerfile ├── config ├── prometheus │ ├── kustomization.yaml │ └── monitor.yaml ├── telemetry-proxy │ ├── kustomization.yaml │ ├── telemetry-proxy-extra-config.yaml │ └── service.yaml ├── certmanager │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ └── certificate.yaml ├── webhooks │ ├── kustomization.yaml │ ├── services.yaml │ ├── kustomizeconfig.yaml │ └── manifests.yaml ├── scorecard │ ├── bases │ │ └── config.yaml │ ├── patches │ │ ├── basic.config.yaml │ │ └── olm.config.yaml │ └── kustomization.yaml ├── samples │ ├── kustomization.yaml │ └── operator_v1alpha1_lumigo.yaml ├── watchdog │ ├── kustomization.yaml │ └── deployment.yaml ├── default │ ├── manager_config_patch.yaml │ ├── manager_pin_injector_version_patch.yaml │ ├── webhooks_cainjection_patch.yaml │ ├── manager_webhook_patch.yaml │ ├── manager_auth_proxy_patch.yaml │ └── kustomization.yaml ├── manifests │ └── kustomization.yaml ├── crd │ ├── patches │ │ ├── cainjection_in_lumigoes.yaml │ │ └── webhook_in_lumigoes.yaml │ ├── kustomizeconfig.yaml │ └── kustomization.yaml ├── manager │ └── kustomization.yaml └── rbac │ ├── service_account.yaml │ ├── auth_proxy_client_clusterrole.yaml │ ├── role_binding.yaml │ ├── auth_proxy_role_binding.yaml │ ├── leader_election_role_binding.yaml │ ├── auth_proxy_role.yaml │ ├── auth_proxy_service.yaml │ ├── lumigo_viewer_role.yaml │ ├── kustomization.yaml │ ├── lumigo_editor_role.yaml │ ├── leader_election_role.yaml │ └── role.yaml ├── images ├── lumigo.png └── lumigo.svg ├── controller ├── src │ ├── types │ │ └── autotrace.go │ ├── api │ │ └── v1alpha1 │ │ │ ├── lumigo_webhook.go │ │ │ ├── groupversion_info.go │ │ │ ├── lumigo_events.go │ │ │ └── lumigo_webhook_suite_test.go │ ├── controllers │ │ ├── internal │ │ │ └── sorting │ │ │ │ ├── sorting_lumigo.go │ │ │ │ ├── sorting_batchv1.go │ │ │ │ └── sorting_appsv1.go │ │ └── telemetryproxyconfigs │ │ │ └── namespace_monitoring_configs.go │ ├── hack │ │ └── boilerplate.go.txt │ └── go.mod ├── Dockerfile └── docker │ └── entrypoint.sh ├── tools ├── tools.go └── go.mod ├── .dockerignore ├── scripts └── ci_deploy.sh ├── go.work ├── .grype.yaml ├── docs └── ecr-public-gallery │ ├── LumigoKubernetesOperatorImage │ ├── Usage.md │ └── About.md │ ├── LumigoTelemetryProxyImage │ ├── Usage.md │ └── About.md │ ├── LumigoAutotraceImage │ ├── About.md │ └── Usage.md │ └── README.md ├── .gitignore ├── PROJECT ├── watchdog ├── Dockerfile ├── docker │ └── entrypoint.sh └── src │ ├── main.go │ ├── config │ └── config.go │ ├── watchers │ ├── utils.go │ └── watchdog_k8s_context.go │ └── go.mod ├── RELEASE.md └── .circleci └── config.yml /VERSION: -------------------------------------------------------------------------------- 1 | 69 -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @mmanciop 2 | @GuyMoses -------------------------------------------------------------------------------- /charts/lumigo-operator/charts/.gitignore: -------------------------------------------------------------------------------- 1 | *.tgz -------------------------------------------------------------------------------- /kube-rbac-proxy/VERSION.kube-rbac-proxy: -------------------------------------------------------------------------------- 1 | v0.14.2 -------------------------------------------------------------------------------- /tests/quickstart/resources/.gitignore: -------------------------------------------------------------------------------- 1 | test-runs/ -------------------------------------------------------------------------------- /telemetryproxy/src/.gitignore: -------------------------------------------------------------------------------- 1 | .tools/ 2 | dist/ 3 | bin/ 4 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/resources/.gitignore: -------------------------------------------------------------------------------- 1 | test-runs/ -------------------------------------------------------------------------------- /config/prometheus/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - monitor.yaml 3 | -------------------------------------------------------------------------------- /telemetryproxy/src/README.md: -------------------------------------------------------------------------------- 1 | # Telemetry-proxy build of the OpenTelemetry Collector -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/Makefile: -------------------------------------------------------------------------------- 1 | include ../../Makefile.Common -------------------------------------------------------------------------------- /images/lumigo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lumigo-io/lumigo-kubernetes-operator/HEAD/images/lumigo.png -------------------------------------------------------------------------------- /kube-rbac-proxy/VERSION.base-image: -------------------------------------------------------------------------------- 1 | sha256:92d40eea0b5307a94f2ebee3e94095e704015fb41e35fc1fcbd1d151cc282222 -------------------------------------------------------------------------------- /config/telemetry-proxy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - service.yaml 3 | - telemetry-proxy-extra-config.yaml 4 | -------------------------------------------------------------------------------- /telemetryproxy/.gitignore: -------------------------------------------------------------------------------- 1 | # in case the makefile target breaks and does not clean up this file properly 2 | Dockerfile.cross -------------------------------------------------------------------------------- /config/certmanager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - certificate.yaml 3 | 4 | configurations: 5 | - kustomizeconfig.yaml 6 | -------------------------------------------------------------------------------- /config/webhooks/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manifests.yaml 3 | - services.yaml 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /.github/file-filters.yaml: -------------------------------------------------------------------------------- 1 | # To be used in conjunction with the https://github.com/dorny/paths-filter GitHub action 2 | 3 | new-release: 4 | - VERSION -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/testdata/invalid_config.yaml: -------------------------------------------------------------------------------- 1 | k8sobjects/invalid_resource: 2 | objects: 3 | - name: fake_resource 4 | mode: watch -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | -------------------------------------------------------------------------------- /config/scorecard/bases/config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scorecard.operatorframework.io/v1alpha3 2 | kind: Configuration 3 | metadata: 4 | name: config 5 | stages: 6 | - parallel: true 7 | tests: [] 8 | -------------------------------------------------------------------------------- /.github/workflows/scripts/increase_version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | current_version=$(git show HEAD:VERSION) 4 | next_version=$((current_version+1)) 5 | 6 | echo -n "${next_version}" > VERSION -------------------------------------------------------------------------------- /config/samples/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## Append samples you want in your CSV to this file as resources ## 2 | resources: 3 | - operator_v1alpha1_lumigo.yaml 4 | #+kubebuilder:scaffold:manifestskustomizesamples 5 | -------------------------------------------------------------------------------- /controller/src/types/autotrace.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type AutoTraceSettings struct { 4 | IsAutoTraced bool 5 | TracesEnabled bool 6 | LogsEnabled bool 7 | SecretName string 8 | SecretKey string 9 | } 10 | -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | package tools 5 | 6 | import ( 7 | _ "github.com/tcnksm/ghr" 8 | _ "go.opentelemetry.io/collector/cmd/builder" 9 | _ "golang.org/x/tools/cmd/goimports" 10 | ) 11 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/testdata/pull_resource_version_config.yaml: -------------------------------------------------------------------------------- 1 | k8sobjects: 2 | objects: 3 | - name: pods 4 | mode: pull 5 | resource_version: "1" 6 | - name: events 7 | mode: pull 8 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | WORKDIR /code 4 | 5 | COPY ./app.py /code/app.py 6 | 7 | LABEL distro-version='DEV' 8 | 9 | CMD ["python", "app.py", "something to say to the logs", "json"] -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file 2 | # Ignore build and test binaries. 3 | .github/ 4 | bin/ 5 | charts/ 6 | config/ 7 | images/ 8 | docs/ 9 | testbin/ 10 | tests/ 11 | tools/ -------------------------------------------------------------------------------- /config/watchdog/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - deployment.yaml 3 | 4 | apiVersion: kustomize.config.k8s.io/v1beta1 5 | kind: Kustomization 6 | images: 7 | - name: watchdog 8 | newName: host.docker.internal:5000/watchdog 9 | newTag: latest -------------------------------------------------------------------------------- /config/default/manager_config_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/metadata.yaml: -------------------------------------------------------------------------------- 1 | type: k8sobjects 2 | 3 | status: 4 | class: receiver 5 | stability: 6 | beta: [logs] 7 | distributions: [contrib, splunk, sumo] 8 | codeowners: 9 | active: [dmitryax, hvaghani221, TylerHelmuth] -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/express/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18 2 | WORKDIR /home/node/app 3 | RUN chown -R node:node /home/node/app 4 | USER 1000 5 | COPY package*.json ./ 6 | RUN npm install 7 | COPY . . 8 | EXPOSE 3000 9 | CMD [ "npm", "start" ] 10 | -------------------------------------------------------------------------------- /config/manifests/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # These resources constitute the fully configured set of manifests 2 | # used to generate the 'manifests/' directory in a bundle. 3 | resources: 4 | - bases/lumigo.clusterserviceversion.yaml 5 | - ../default 6 | - ../samples 7 | - ../scorecard 8 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18 2 | 3 | WORKDIR /code 4 | 5 | COPY ./app.js /code/app.js 6 | COPY ./package.json /code/package.json 7 | 8 | RUN npm i --omit=dev 9 | 10 | LABEL distro-version='DEV' 11 | 12 | CMD ["npm", "run", "start"] -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18 2 | 3 | WORKDIR /code 4 | 5 | COPY ./app.js /code/app.js 6 | COPY ./package.json /code/package.json 7 | 8 | RUN npm i --omit=dev 9 | 10 | LABEL distro-version='DEV' 11 | 12 | CMD ["npm", "run", "start"] -------------------------------------------------------------------------------- /controller/src/api/v1alpha1/lumigo_webhook.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ctrl "sigs.k8s.io/controller-runtime" 4 | 5 | func (r *Lumigo) SetupWebhookWithManager(mgr ctrl.Manager) error { 6 | return ctrl.NewWebhookManagedBy(mgr). 7 | For(r). 8 | Complete() 9 | } 10 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-js-test-server", 3 | "version": "1.0.0", 4 | "license": "ISC", 5 | "dependencies": { 6 | "express": "^4.18.1" 7 | }, 8 | "scripts": { 9 | "start": "node app.js" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /charts/lumigo-operator/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: kube-state-metrics 3 | repository: https://prometheus-community.github.io/helm-charts 4 | version: 5.27.0 5 | digest: sha256:6d83858e70820ffa627bbbe62d4c95dbefe2c8b05e5b2bf2cd8d932d8114f060 6 | generated: "2024-11-27T21:03:23.027531+02:00" 7 | -------------------------------------------------------------------------------- /scripts/ci_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | pushd "$(dirname "$0")" &> /dev/null 5 | # Go back one spot because we are on scripts dir. The other scripts assume you are in the root folder 6 | cd .. 7 | ../utils/common_bash/defaults/ci_deploy.sh lumigo-kubernetes-operator 8 | popd &> /dev/null -------------------------------------------------------------------------------- /telemetryproxy/src/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lumigo-io/lumigo-kubernetes-operator/telemetryproxy 2 | 3 | go 1.20 4 | 5 | replace "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sdataenricherprocessor v0.116.0" => ./processor/k8sdataenricherprocessor 6 | 7 | replace tools => ./internal/tools 8 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:generate mdatagen metadata.yaml 5 | 6 | package k8sobjectsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sobjectsreceiver" 7 | -------------------------------------------------------------------------------- /config/scorecard/patches/basic.config.yaml: -------------------------------------------------------------------------------- 1 | - op: add 2 | path: /stages/0/tests/- 3 | value: 4 | entrypoint: 5 | - scorecard-test 6 | - basic-check-spec 7 | image: quay.io/operator-framework/scorecard-test:v1.26.0 8 | labels: 9 | suite: basic 10 | test: basic-check-spec-test 11 | -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.23.0 2 | 3 | toolchain go1.23.8 4 | 5 | use ( 6 | ./controller/src 7 | // ./telemetryproxy/src/processor/k8sdataenricherprocessor 8 | // ./telemetryproxy/src/receiver/lumigooperatorheartbeatreceiver 9 | // ./telemetryproxy/src/internal/tools 10 | ./tests 11 | ./tools 12 | ./watchdog/src 13 | ) 14 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: lumigo-kubernetes-operator 5 | labels: 6 | {{- include "helm.labels" . | nindent 4 }} 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/internal/metadata/generated_status.go: -------------------------------------------------------------------------------- 1 | // Code generated by mdatagen. DO NOT EDIT. 2 | 3 | package metadata 4 | 5 | import ( 6 | "go.opentelemetry.io/collector/component" 7 | ) 8 | 9 | var Type = component.MustNewType("k8sobjects") 10 | const LogsStability = component.StabilityLevelBeta -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_lumigoes.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | name: lumigoes.operator.lumigo.io 8 | -------------------------------------------------------------------------------- /config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | images: 6 | - name: controller 7 | newName: host.docker.internal:5000/controller 8 | newTag: latest 9 | - name: telemetry-proxy 10 | newName: host.docker.internal:5000/telemetry-proxy 11 | newTag: latest 12 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/testdata/config_watch_resource_version.yaml: -------------------------------------------------------------------------------- 1 | k8sobjects: 2 | objects: 3 | - name: events 4 | mode: watch 5 | group: events.k8s.io 6 | namespaces: [default] 7 | - name: events 8 | mode: watch 9 | group: events.k8s.io 10 | namespaces: [default] 11 | resource_version: "2" -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # End-to-end tests 2 | 3 | The goal of these tests is to validate the Lumigo operator's behavior across various Kubernetes flavors. 4 | 5 | These tests assume: 6 | 7 | 1. A valid `kubectl` configuration available in the home directory of the user 8 | 2. A Lumigo operator installed and up-and-running into the Kubernetes cluster referenced by the `kubectl` configuration -------------------------------------------------------------------------------- /tests/quickstart/resources/kind-config.yaml.tpl: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | nodes: 4 | - role: control-plane 5 | kubeadmConfigPatches: 6 | - | 7 | kind: InitConfiguration 8 | nodeRegistration: 9 | kubeletExtraArgs: 10 | system-reserved: memory=4Gi 11 | register-with-taints: "some-test-taint=voila:NoExecute" -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-js-test-client", 3 | "version": "1.0.0", 4 | "license": "ISC", 5 | "dependencies": { 6 | "@opentelemetry/api": "^1.4.1", 7 | "axios": "^1.1.2", 8 | "winston": "3.13.0", 9 | "@opentelemetry/winston-transport": "0.3.0" 10 | }, 11 | "scripts": { 12 | "start": "node app.js" 13 | } 14 | } -------------------------------------------------------------------------------- /config/default/manager_pin_injector_version_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: manager 10 | env: 11 | - name: LUMIGO_INJECTOR_IMAGE 12 | value: public.ecr.aws/lumigo/lumigo-autotrace:latest # CHANGE this to the image you want to use -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: serviceaccount 6 | app.kubernetes.io/instance: controller-manager 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | app.kubernetes.io/managed-by: kustomize 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kube-service", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node src/index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "express": "^4.18.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /charts/lumigo-operator/samples/operator_v1alpha1_lumigo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: operator.lumigo.io/v1alpha1 2 | kind: Lumigo 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: lumigo 6 | app.kubernetes.io/instance: lumigo 7 | app.kubernetes.io/part-of: lumigo 8 | app.kubernetes.io/created-by: lumigo 9 | name: lumigo 10 | spec: 11 | lumigoToken: 12 | secretRef: 13 | name: lumigo-credentials 14 | key: token 15 | -------------------------------------------------------------------------------- /.github/workflows/check-pr-title.yml: -------------------------------------------------------------------------------- 1 | name: Check PR title 2 | on: 3 | pull_request_target: 4 | types: 5 | - opened 6 | - reopened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | permissions: 14 | statuses: write 15 | steps: 16 | - uses: aslafy-z/conventional-pr-title-action@v3 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/scripts/validate_version_increment.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | previous_version=$(git show HEAD~1:VERSION) 4 | current_version=$(git show HEAD:VERSION) 5 | 6 | if [[ $((current_version)) == $((previous_version+1)) ]] 7 | then 8 | exit 0 9 | else 10 | echo "Version '${current_version}' is not a linear increment from the previous '${previous_version}' version; expected new version: '$((previous_version+1))'" 11 | exit 1 12 | fi -------------------------------------------------------------------------------- /.grype.yaml: -------------------------------------------------------------------------------- 1 | ignore: 2 | # Only required until gomplate is released with https://github.com/hairyhenderson/gomplate/issues/1960 resolved 3 | # TODO: Remove this once the above issue is resolved 4 | - vulnerability: GHSA-449p-3h89-pw88 5 | - vulnerability: GHSA-mw99-9chc-xw7r 6 | # Required until the collector can be bumped to a version that does not use 7 | # the vulnerable version of the `github.com/docker/docker` module 8 | - vulnerability: GHSA-v23v-6jw2-98fq 9 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/metrics-reader-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: {{ include "helm.fullname" . }}-metrics-reader 5 | labels: 6 | {{- include "helm.labels" . | nindent 4 }} 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | rules: 11 | - nonResourceURLs: 12 | - /metrics 13 | verbs: 14 | - get -------------------------------------------------------------------------------- /charts/lumigo-operator/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /config/scorecard/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - bases/config.yaml 3 | patchesJson6902: 4 | - path: patches/basic.config.yaml 5 | target: 6 | group: scorecard.operatorframework.io 7 | version: v1alpha3 8 | kind: Configuration 9 | name: config 10 | - path: patches/olm.config.yaml 11 | target: 12 | group: scorecard.operatorframework.io 13 | version: v1alpha3 14 | kind: Configuration 15 | name: config 16 | #+kubebuilder:scaffold:patchesJson6902 17 | -------------------------------------------------------------------------------- /config/certmanager/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This configuration is for teaching kustomize how to update name ref and var substitution 2 | nameReference: 3 | - kind: Issuer 4 | group: cert-manager.io 5 | fieldSpecs: 6 | - kind: Certificate 7 | group: cert-manager.io 8 | path: spec/issuerRef/name 9 | 10 | varReference: 11 | - kind: Certificate 12 | group: cert-manager.io 13 | path: spec/commonName 14 | - kind: Certificate 15 | group: cert-manager.io 16 | path: spec/dnsNames 17 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_lumigoes.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: lumigoes.operator.lumigo.io 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: 16 | - v1 17 | -------------------------------------------------------------------------------- /telemetryproxy/docker/etc/common-config.yaml: -------------------------------------------------------------------------------- 1 | processors: 2 | filter/filter-prom-metrics: 3 | metrics: 4 | exclude: 5 | match_type: regexp 6 | metric_names: 7 | # Exclude Prometheus scrape metrics 8 | - 'scrape_.+' 9 | - 'up' 10 | # Exclude Go runtime metrics 11 | - 'go_.+' 12 | # Exclude API server metrics 13 | - 'apiserver_.+' 14 | - 'authentication_token_.+' 15 | - 'aggregator_discovery_aggregation_count' 16 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrole 6 | app.kubernetes.io/instance: metrics-reader 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | app.kubernetes.io/managed-by: kustomize 11 | name: metrics-reader 12 | rules: 13 | - nonResourceURLs: 14 | - "/metrics" 15 | verbs: 16 | - get 17 | -------------------------------------------------------------------------------- /docs/ecr-public-gallery/LumigoKubernetesOperatorImage/Usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | This image delivers the controller part of the [Lumigo Kubernetes Operator](https://docs.lumigo.io/docs/lumigo-kubernetes-operator), and should be deployed using the `lumigo-operator` Helm chart available through [ArtifactHub](https://artifacthub.io/packages/helm/lumigo-operator/lumigo-operator). 4 | 5 | For information on how to configure the Lumigo Kubernetes operator, refer to the [documentation on GitHub](https://github.com/lumigo-io/lumigo-kubernetes-operator/). 6 | -------------------------------------------------------------------------------- /docs/ecr-public-gallery/LumigoTelemetryProxyImage/Usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | This image delivers the telemetry-proxy part of the [Lumigo Kubernetes Operator](https://docs.lumigo.io/docs/lumigo-kubernetes-operator), and should be deployed using the `lumigo-operator` Helm chart available through [ArtifactHub](https://artifacthub.io/packages/helm/lumigo-operator/lumigo-operator). 4 | 5 | For information on how to configure the Lumigo Kubernetes operator, refer to the [documentation on GitHub](https://github.com/lumigo-io/lumigo-kubernetes-operator/). 6 | -------------------------------------------------------------------------------- /config/default/webhooks_cainjection_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: admissionregistration.k8s.io/v1 2 | kind: MutatingWebhookConfiguration 3 | metadata: 4 | name: injector-webhook-configuration 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | --- 8 | apiVersion: admissionregistration.k8s.io/v1 9 | kind: MutatingWebhookConfiguration 10 | metadata: 11 | name: defaulter-webhook-configuration 12 | annotations: 13 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 14 | -------------------------------------------------------------------------------- /controller/src/controllers/internal/sorting/sorting_lumigo.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | import ( 4 | operatorv1alpha1 "github.com/lumigo-io/lumigo-kubernetes-operator/api/v1alpha1" 5 | ) 6 | 7 | // To be used with sort.Sort 8 | type ByCreationTime []operatorv1alpha1.Lumigo 9 | 10 | func (s ByCreationTime) Len() int { 11 | return len(s) 12 | } 13 | func (s ByCreationTime) Swap(i, j int) { 14 | s[i], s[j] = s[j], s[i] 15 | } 16 | 17 | func (s ByCreationTime) Less(i, j int) bool { 18 | return s[i].CreationTimestamp.Before(&s[j].CreationTimestamp) 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | bin/ 18 | !telemetryproxy/bin 19 | 20 | node_modules 21 | test.out 22 | .vscode 23 | 24 | # Temporary files created by make docker-buildx 25 | Dockerfile.*.cross 26 | 27 | .idea 28 | .DS_Store 29 | 30 | **/__debug_bin* 31 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/express/src/index.js: -------------------------------------------------------------------------------- 1 | 2 | console.log("started"); 3 | 4 | const express = require('express') 5 | const app = express() 6 | const port = 3000 7 | 8 | app.get('/', (req, res) => { 9 | console.log("print something...") 10 | res.send('Hello World!!! a') 11 | }) 12 | 13 | app.get('/throw-error', (req, res) => { 14 | throw new Error("my error"); 15 | }) 16 | 17 | app.get('/null-error', (req, res) => { 18 | access.nothing(); 19 | }) 20 | 21 | app.listen(port, () => { 22 | console.log(`Example app listening on port ${port}`) 23 | }) -------------------------------------------------------------------------------- /docs/ecr-public-gallery/LumigoAutotraceImage/About.md: -------------------------------------------------------------------------------- 1 | # Lumigo automatic tracing for Amazon ECS 2 | 3 | This image provides automatic injection for the Lumigo OpenTelemetry distributions for Java, Node.js and Python using the [respective Lumigo OpenTelemetry distributions](https://docs.lumigo.io/docs/containerized-applications). 4 | 5 | This container image is used by: 6 | 7 | * the [Lumigo Kubernetes operator](https://docs.lumigo.io/docs/lumigo-kubernetes-operator) 8 | * the Amazon ECS tracing provided by the [Lumigo CDK constructs](https://docs.lumigo.io/docs/aws-cdk#monitoring-aws-cdk-2-applications) 9 | -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | domain: lumigo.io 2 | layout: 3 | - go.kubebuilder.io/v3 4 | plugins: 5 | manifests.sdk.operatorframework.io/v2: {} 6 | scorecard.sdk.operatorframework.io/v2: {} 7 | projectName: lumigo 8 | repo: github.com/lumigo-io/lumigo-kubernetes-operator 9 | resources: 10 | - api: 11 | crdVersion: v1 12 | namespaced: true 13 | controller: true 14 | domain: lumigo.io 15 | group: operator 16 | kind: Lumigo 17 | path: github.com/lumigo-io/lumigo-kubernetes-operator/api/v1alpha1 18 | version: v1alpha1 19 | webhooks: 20 | defaulting: true 21 | webhookVersion: v1 22 | version: "3" 23 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/resources/kind-config.yaml.tpl: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | nodes: 4 | - role: control-plane 5 | labels: 6 | node-type: really-good 7 | extraMounts: 8 | - hostPath: '{{OTLP_SINK_CONFIG_VOLUME_PATH}}' 9 | containerPath: /lumigo/otlp-sink/config 10 | - hostPath: '{{OTLP_SINK_DATA_VOLUME_PATH}}' 11 | containerPath: /lumigo/otlp-sink/data 12 | kubeadmConfigPatches: 13 | - | 14 | kind: InitConfiguration 15 | nodeRegistration: 16 | kubeletExtraArgs: 17 | system-reserved: memory=4Gi -------------------------------------------------------------------------------- /config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | version: v1 8 | group: apiextensions.k8s.io 9 | path: spec/conversion/webhook/clientConfig/service/name 10 | 11 | namespace: 12 | - kind: CustomResourceDefinition 13 | version: v1 14 | group: apiextensions.k8s.io 15 | path: spec/conversion/webhook/clientConfig/service/namespace 16 | create: false 17 | 18 | varReference: 19 | - path: metadata/annotations 20 | -------------------------------------------------------------------------------- /config/webhooks/services.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: webhooks-service 7 | app.kubernetes.io/instance: webhooks-service 8 | app.kubernetes.io/component: lumigo 9 | app.kubernetes.io/created-by: lumigo 10 | app.kubernetes.io/part-of: lumigo 11 | app.kubernetes.io/managed-by: kustomize 12 | name: webhooks-service 13 | namespace: system 14 | spec: 15 | ports: 16 | - port: 443 17 | protocol: TCP 18 | targetPort: 9443 19 | selector: 20 | control-plane: controller-manager 21 | type: ClusterIP 22 | -------------------------------------------------------------------------------- /controller/src/hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 Lumigo. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ -------------------------------------------------------------------------------- /config/default/manager_webhook_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | ports: 12 | - containerPort: 9443 13 | name: webhook-server 14 | protocol: TCP 15 | volumeMounts: 16 | - mountPath: /tmp/k8s-webhook-server/serving-certs 17 | name: cert 18 | readOnly: true 19 | volumes: 20 | - name: cert 21 | secret: 22 | defaultMode: 420 23 | secretName: webhook-server-cert 24 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrolebinding 6 | app.kubernetes.io/instance: manager-rolebinding 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | app.kubernetes.io/managed-by: kustomize 11 | name: manager-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: ClusterRole 15 | name: manager-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: controller-manager 19 | namespace: system 20 | -------------------------------------------------------------------------------- /config/telemetry-proxy/telemetry-proxy-extra-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: telemetry-proxy-extra-config 5 | labels: 6 | app.kubernetes.io/name: telemetry-proxy-extra-config 7 | app.kubernetes.io/instance: telemetry-proxy-extra-config 8 | app.kubernetes.io/component: telemetry-proxy 9 | app.kubernetes.io/created-by: lumigo 10 | app.kubernetes.io/part-of: lumigo 11 | data: 12 | extra-config.json: | 13 | { 14 | "batchProcessor": { 15 | "enabled": false, 16 | "size": "200", 17 | "maxSize": "200", 18 | "timeout": "200ms" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/server/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | express() 4 | .use(express.json()) 5 | .get('/health', async (_, res) => { 6 | res.status(200).send(); 7 | }) 8 | .post('/api/checkout', async (req, res) => { 9 | const order = req.body; 10 | console.log(`Received request: ${JSON.stringify(order)}`); 11 | 12 | if (Math.random() < 0.3) { 13 | res.status(500).send({ 14 | orderProcessed: false 15 | }); 16 | } else { 17 | res.status(200).send({ 18 | orderProcessed: true 19 | }); 20 | } 21 | }) 22 | .listen(process.env.SERVER_PORT || 5000); 23 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrolebinding 6 | app.kubernetes.io/instance: proxy-rolebinding 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | app.kubernetes.io/managed-by: kustomize 11 | name: proxy-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: ClusterRole 15 | name: proxy-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: controller-manager 19 | namespace: system 20 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/metrics-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "helm.fullname" . }}-controller-manager-metrics-service 5 | labels: 6 | {{- include "helm.labels" . | nindent 4 }} 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | control-plane: controller-manager 11 | spec: 12 | type: {{ .Values.metricsService.type }} 13 | selector: 14 | control-plane: controller-manager 15 | {{- include "helm.selectorLabels" . | nindent 4 }} 16 | ports: 17 | {{- .Values.metricsService.ports | toYaml | nindent 2 -}} -------------------------------------------------------------------------------- /config/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: rolebinding 6 | app.kubernetes.io/instance: leader-election-rolebinding 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | app.kubernetes.io/managed-by: kustomize 11 | name: leader-election-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: Role 15 | name: leader-election-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: controller-manager 19 | namespace: system 20 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrole 6 | app.kubernetes.io/instance: proxy-role 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | app.kubernetes.io/managed-by: kustomize 11 | name: proxy-role 12 | rules: 13 | - apiGroups: 14 | - authentication.k8s.io 15 | resources: 16 | - tokenreviews 17 | verbs: 18 | - create 19 | - apiGroups: 20 | - authorization.k8s.io 21 | resources: 22 | - subjectaccessreviews 23 | verbs: 24 | - create 25 | -------------------------------------------------------------------------------- /docs/ecr-public-gallery/README.md: -------------------------------------------------------------------------------- 1 | # Lumigo Kubernetes operator documentation on Amazon ECR Public Gallery 2 | 3 | The files in this folder are used to populate the image descriptions on the Amazon ECR Public Gallery: 4 | 5 | * [`lumigo/lumigo-autotrace`](https://gallery.ecr.aws/lumigo/lumigo-autotrace) 6 | * [`lumigo/lumigo-kubernetes-operator`](https://gallery.ecr.aws/lumigo/lumigo-kubernetes-operator) 7 | * [`lumigo/lumigo-kubernetes-telemetry-proxy`](https://gallery.ecr.aws/lumigo/lumigo-kubernetes-telemetry-proxy) 8 | 9 | The logic that uploads these descriptions is in a private repository, together with the build automation that create the matching ECR repositories. 10 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | app.kubernetes.io/name: service 7 | app.kubernetes.io/instance: controller-manager-metrics-service 8 | app.kubernetes.io/component: kube-rbac-proxy 9 | app.kubernetes.io/created-by: lumigo 10 | app.kubernetes.io/part-of: lumigo 11 | app.kubernetes.io/managed-by: kustomize 12 | name: controller-manager-metrics-service 13 | namespace: system 14 | spec: 15 | ports: 16 | - name: https 17 | port: 9443 18 | protocol: TCP 19 | targetPort: https 20 | selector: 21 | control-plane: controller-manager 22 | type: ClusterIP 23 | -------------------------------------------------------------------------------- /controller/src/controllers/internal/sorting/sorting_batchv1.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | import ( 4 | batchv1 "k8s.io/api/batch/v1" 5 | ) 6 | 7 | type ByCronJobName []batchv1.CronJob 8 | 9 | func (s ByCronJobName) Len() int { 10 | return len(s) 11 | } 12 | func (s ByCronJobName) Swap(i, j int) { 13 | s[i], s[j] = s[j], s[i] 14 | } 15 | 16 | func (s ByCronJobName) Less(i, j int) bool { 17 | return s[i].Name < s[j].Name 18 | } 19 | 20 | type ByJobName []batchv1.Job 21 | 22 | func (s ByJobName) Len() int { 23 | return len(s) 24 | } 25 | func (s ByJobName) Swap(i, j int) { 26 | s[i], s[j] = s[j], s[i] 27 | } 28 | 29 | func (s ByJobName) Less(i, j int) bool { 30 | return s[i].Name < s[j].Name 31 | } 32 | -------------------------------------------------------------------------------- /charts/lumigo-operator/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: lumigo-operator 3 | description: Chart to deploy the Lumigo Kubernetes Operator 4 | type: application 5 | keywords: 6 | - observability 7 | - monitoring 8 | - distributed tracing 9 | - opentelemetry 10 | home: https://github.com/lumigo-io/lumigo-kubernetes-operator/ 11 | icon: https://raw.githubusercontent.com/lumigo-io/lumigo-kubernetes-operator/main/images/lumigo.png 12 | version: '0' 13 | appVersion: '0' 14 | dependencies: 15 | - name: kube-state-metrics 16 | version: 5.27.0 17 | repository: https://prometheus-community.github.io/helm-charts 18 | condition: "{{ and .Values.clusterCollection.metrics.enabled .Values.kubeStateMetrics.install }}" -------------------------------------------------------------------------------- /telemetryproxy/src/internal/tools/empty_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package tools 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for the Lumigo Kubernetes Operator 4 | title: '' 5 | labels: enhancement 6 | 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /tests/quickstart/internal/load_docker_image.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "sigs.k8s.io/e2e-framework/pkg/env" 8 | "sigs.k8s.io/e2e-framework/pkg/envconf" 9 | "sigs.k8s.io/e2e-framework/pkg/envfuncs" 10 | ) 11 | 12 | func LoadDockerImageArchiveToCluster(kindClusterName, containerImageArchivePath string, logger *log.Logger) env.Func { 13 | return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { 14 | logger.Printf("Loading the image archive '%[2]s' into the Kind cluster '%[1]v'\n", kindClusterName, containerImageArchivePath) 15 | delegate := envfuncs.LoadImageArchiveToCluster(kindClusterName, containerImageArchivePath) 16 | return delegate(ctx, cfg) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /config/rbac/lumigo_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view lumigoes. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: lumigo-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: lumigo 10 | app.kubernetes.io/part-of: lumigo 11 | app.kubernetes.io/managed-by: kustomize 12 | name: lumigo-viewer-role 13 | rules: 14 | - apiGroups: 15 | - operator.lumigo.io 16 | resources: 17 | - lumigoes 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - operator.lumigo.io 24 | resources: 25 | - lumigoes/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/internal/load_docker_image.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "sigs.k8s.io/e2e-framework/pkg/env" 8 | "sigs.k8s.io/e2e-framework/pkg/envconf" 9 | "sigs.k8s.io/e2e-framework/pkg/envfuncs" 10 | ) 11 | 12 | func LoadDockerImageArchiveToCluster(kindClusterName, containerImageArchivePath string, logger *log.Logger) env.Func { 13 | return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { 14 | logger.Printf("Loading the image archive '%[2]s' into the Kind cluster '%[1]v'\n", kindClusterName, containerImageArchivePath) 15 | delegate := envfuncs.LoadImageArchiveToCluster(kindClusterName, containerImageArchivePath) 16 | return delegate(ctx, cfg) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /config/telemetry-proxy/service.yaml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: telemetry-proxy-service 6 | labels: 7 | app.kubernetes.io/name: telemetry-proxy-service 8 | app.kubernetes.io/instance: telemetry-proxy-service 9 | app.kubernetes.io/component: telemetry-proxy 10 | app.kubernetes.io/created-by: lumigo 11 | app.kubernetes.io/part-of: lumigo 12 | spec: 13 | type: ClusterIP 14 | ports: 15 | - name: otlphttp 16 | protocol: TCP 17 | # TODO Can we use generated certificates to make it HTTPS? 18 | # If we used self-signed certs, how would we pass the CA to OTLP exporters in client apps? 19 | port: 80 20 | targetPort: otlphttp 21 | selector: 22 | control-plane: controller-manager -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve the Lumigo Kubernetes Operator 4 | title: '' 5 | labels: bug 6 | 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 1. Go to '...' 15 | 2. Click on '....' 16 | 3. Scroll down to '....' 17 | 4. See an error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Runtime details** 23 | - runtime version (node8, 10x, 12).. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /config/samples/operator_v1alpha1_lumigo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: lumigo-credentials 5 | stringData: 6 | # Kubectl won't allow you to deploy this dangling anchor. 7 | # Get the actual value from Lumigo following this documentation: https://docs.lumigo.io/docs/lumigo-tokens 8 | token: *lumigo-token # Example: t_123456789012345678901 9 | --- 10 | apiVersion: operator.lumigo.io/v1alpha1 11 | kind: Lumigo 12 | metadata: 13 | labels: 14 | app.kubernetes.io/name: lumigo 15 | app.kubernetes.io/instance: lumigo-sample 16 | app.kubernetes.io/part-of: lumigo 17 | app.kubernetes.io/created-by: lumigo 18 | name: lumigo-sample 19 | spec: 20 | lumigoToken: 21 | secretRef: 22 | name: lumigo-credentials 23 | key: token 24 | -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | # All RBAC will be applied under this service account in 3 | # the deployment namespace. You may comment out this resource 4 | # if your manager will use a service account that exists at 5 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding 6 | # subjects if changing service account names. 7 | - service_account.yaml 8 | - role.yaml 9 | - role_binding.yaml 10 | - leader_election_role.yaml 11 | - leader_election_role_binding.yaml 12 | # Comment the following 4 lines if you want to disable 13 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 14 | # which protects your /metrics endpoint. 15 | - auth_proxy_service.yaml 16 | - auth_proxy_role.yaml 17 | - auth_proxy_role_binding.yaml 18 | - auth_proxy_client_clusterrole.yaml 19 | -------------------------------------------------------------------------------- /config/rbac/lumigo_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit lumigoes. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: lumigo-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: lumigo 10 | app.kubernetes.io/part-of: lumigo 11 | app.kubernetes.io/managed-by: kustomize 12 | name: lumigo-editor-role 13 | rules: 14 | - apiGroups: 15 | - operator.lumigo.io 16 | resources: 17 | - lumigoes 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - operator.lumigo.io 28 | resources: 29 | - lumigoes/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdk", 3 | "version": "0.1.0", 4 | "bin": { 5 | "cdk": "bin/cdk.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@types/jest": "^29.5.11", 15 | "@types/node": "20.11.0", 16 | "aws-cdk": "2.118.0", 17 | "jest": "^29.7.0", 18 | "ts-jest": "^29.1.0", 19 | "ts-node": "^10.9.2", 20 | "typescript": "~5.3.3" 21 | }, 22 | "dependencies": { 23 | "@aws-cdk/lambda-layer-kubectl-v26": "^2.0.1", 24 | "aws-cdk-lib": "2.118.0", 25 | "cdk8s": "^2.68.25", 26 | "cdk8s-plus-26": "^2.18.72", 27 | "constructs": "^10.0.0", 28 | "source-map-support": "^0.5.21" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020", 7 | "dom" 8 | ], 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "alwaysStrict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": false, 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "experimentalDecorators": true, 22 | "strictPropertyInitialization": false, 23 | "typeRoots": [ 24 | "./node_modules/@types" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "cdk.out" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/telemetry-proxy-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "helm.fullname" . }}-telemetry-proxy-service 5 | labels: 6 | {{- include "helm.labels" . | nindent 4 }} 7 | app.kubernetes.io/component: telemetry-proxy 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | control-plane: telemetry-proxy 11 | spec: 12 | type: {{ .Values.metricsService.type }} 13 | selector: 14 | {{- include "helm.selectorLabels" . | nindent 4 }} 15 | control-plane: telemetry-proxy 16 | ports: 17 | - name: otlphttp 18 | protocol: TCP 19 | # TODO Can we use generated certificates to make it HTTPS? 20 | # If we used self-signed certs, how would we pass the CA to OTLP exporters in client apps? 21 | port: 80 22 | targetPort: otlphttp 23 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/operator.lumigo.io_lumigoes.yaml 6 | #+kubebuilder:scaffold:crdkustomizeresource 7 | 8 | patchesStrategicMerge: 9 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 10 | # patches here are for enabling the conversion webhook for each CRD 11 | #- patches/webhook_in_lumigoes.yaml 12 | #+kubebuilder:scaffold:crdkustomizewebhookpatch 13 | 14 | - patches/cainjection_in_lumigoes.yaml 15 | #+kubebuilder:scaffold:crdkustomizecainjectionpatch 16 | 17 | # the following config is for teaching kustomize how to do kustomization for CRDs. 18 | configurations: 19 | - kustomizeconfig.yaml 20 | -------------------------------------------------------------------------------- /config/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Prometheus Monitor Service (Metrics) 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | labels: 7 | control-plane: controller-manager 8 | app.kubernetes.io/name: servicemonitor 9 | app.kubernetes.io/instance: controller-manager-metrics-monitor 10 | app.kubernetes.io/component: metrics 11 | app.kubernetes.io/created-by: lumigo 12 | app.kubernetes.io/part-of: lumigo 13 | app.kubernetes.io/managed-by: kustomize 14 | name: controller-manager-metrics-monitor 15 | namespace: system 16 | spec: 17 | endpoints: 18 | - path: /metrics 19 | port: https 20 | scheme: https 21 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 22 | tlsConfig: 23 | insecureSkipVerify: true 24 | selector: 25 | matchLabels: 26 | control-plane: controller-manager 27 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/cluster-agent-service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.clusterCollection.metrics.enabled }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "helm.fullname" . }}-cluster-agent-service 6 | labels: 7 | {{- include "helm.labels" . | nindent 4 }} 8 | app.kubernetes.io/component: cluster-agent 9 | app.kubernetes.io/created-by: lumigo 10 | app.kubernetes.io/part-of: lumigo 11 | control-plane: cluster-agent 12 | spec: 13 | selector: 14 | {{- include "helm.selectorLabels" . | nindent 4 }} 15 | control-plane: cluster-agent 16 | ports: 17 | - name: prometheus-node-exporter 18 | protocol: TCP 19 | port: {{ .Values.prometheusNodeExporter.service.port }} 20 | targetPort: {{ .Values.prometheusNodeExporter.service.port }} 21 | nodePort: {{ .Values.prometheusNodeExporter.service.nodePort }} 22 | type: NodePort 23 | {{- end }} -------------------------------------------------------------------------------- /tests/quickstart/internal/context.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | type ContextKey string 4 | 5 | var ( 6 | ContextKeyRunId = ContextKey("run-id") 7 | ContextKeyKubernetesClusterName = ContextKey("kubernetes/cluster/name") 8 | ContextKeyLumigoOperatorDebug = ContextKey("lumigo/debug") 9 | ContextKeyLumigoNamespace = ContextKey("lumigo/namespace") 10 | ContextKeyLumigoToken = ContextKey("lumigo/token") 11 | ContextKeyOperatorControllerImage = ContextKey("lumigo/operator/images/controller") 12 | ContextKeyOperatorTelemetryProxyImage = ContextKey("lumigo/operator/images/proxy") 13 | ContextKeySendDataToLumigo = ContextKey("lumigo/upstream/send_data") 14 | ContextQuickstartNamespaces = ContextKey("test-apps/namespace/quickstart") 15 | ) 16 | 17 | func (c ContextKey) String() string { 18 | return "ctx.key:" + string(c) 19 | } 20 | -------------------------------------------------------------------------------- /docs/ecr-public-gallery/LumigoAutotraceImage/Usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | This image contains the latest version of the Lumigo OpenTelemetry distributions for Java, Node.js and Python, alongside the Lumigo Injector, which enables the activation of the Lumigo OpenTelemetry distributions in compatible runtimes inside your containers. 4 | 5 | This container image should be used through: 6 | 7 | * the [Lumigo Kubernetes operator](https://docs.lumigo.io/docs/lumigo-kubernetes-operator) 8 | * the Amazon ECS tracing provided by the [Lumigo CDK constructs](https://docs.lumigo.io/docs/aws-cdk#monitoring-aws-cdk-2-applications) 9 | 10 | If you are interested in how the Lumigo Injector works in conjunction with the Lumigo OpenTelemetry distributions, have a look at ["The Magic Behind the Lumigo Kubernetes Operator"](https://lumigo.io/blog/the-magic-behind-the-lumigo-kubernetes-operator/) on the [Lumigo blog](https://lumigo.io/blog/). -------------------------------------------------------------------------------- /config/webhooks/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # the following config is for teaching kustomize where to look at when substituting vars. 2 | # It requires kustomize v2.1.0 or newer to work properly. 3 | nameReference: 4 | - kind: Service 5 | version: v1 6 | fieldSpecs: 7 | - kind: MutatingWebhookConfiguration 8 | group: admissionregistration.k8s.io 9 | path: webhooks/clientConfig/service/name 10 | - kind: ValidatingWebhookConfiguration 11 | group: admissionregistration.k8s.io 12 | path: webhooks/clientConfig/service/name 13 | 14 | namespace: 15 | - kind: MutatingWebhookConfiguration 16 | group: admissionregistration.k8s.io 17 | path: webhooks/clientConfig/service/namespace 18 | create: true 19 | - kind: ValidatingWebhookConfiguration 20 | group: admissionregistration.k8s.io 21 | path: webhooks/clientConfig/service/namespace 22 | create: true 23 | 24 | varReference: 25 | - path: metadata/annotations 26 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/python/app.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import logging 4 | import json 5 | 6 | logger = logging.getLogger("my-test-logger") 7 | logger.setLevel(logging.INFO) 8 | 9 | # Non-mandatory in our OTEL setup, but recommended for troubleshooting - adds a console handler to see the logs in the console 10 | console_handler = logging.StreamHandler() 11 | console_handler.setLevel(logging.INFO) 12 | logger.addHandler(console_handler) 13 | 14 | while True: 15 | message = sys.argv[1] if len(sys.argv) > 1 else "Hello, World!" 16 | formatter = json.dumps if len(sys.argv) > 2 and sys.argv[2] == "json" else str 17 | logger.info(formatter({"message": message})) 18 | try: 19 | from lumigo_opentelemetry import logger_provider 20 | logger_provider.force_flush() 21 | except Exception as e: 22 | logger.error(f"Failed to flush logs via distro: {e}") 23 | time.sleep(5) -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/lumigooperatorheartbeatreceiver/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Lumigo 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package lumigooperatorheartbeatreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/lumigooperatorheartbeatreceiver" 16 | 17 | type Config struct { 18 | Namespace string `mapstructure:"namespace"` 19 | } 20 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: role 7 | app.kubernetes.io/instance: leader-election-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: lumigo 10 | app.kubernetes.io/part-of: lumigo 11 | app.kubernetes.io/managed-by: kustomize 12 | name: leader-election-role 13 | rules: 14 | - apiGroups: 15 | - "" 16 | resources: 17 | - configmaps 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - create 23 | - update 24 | - patch 25 | - delete 26 | - apiGroups: 27 | - coordination.k8s.io 28 | resources: 29 | - leases 30 | verbs: 31 | - get 32 | - list 33 | - watch 34 | - create 35 | - update 36 | - patch 37 | - delete 38 | - apiGroups: 39 | - "" 40 | resources: 41 | - events 42 | verbs: 43 | - create 44 | - patch 45 | -------------------------------------------------------------------------------- /.github/workflows/trigger-release.yml: -------------------------------------------------------------------------------- 1 | name: Trigger release 2 | on: 3 | workflow_dispatch: 4 | inputs: {} 5 | 6 | jobs: 7 | increase_version: 8 | permissions: 9 | contents: write 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 1 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | with: 16 | ref: main 17 | - name: Increase version 18 | run: .github/workflows/scripts/increase_version.sh 19 | - name: Set Git config up 20 | run: | 21 | git config --global user.name "Lumigo Bot" 22 | git config --global user.email "bot@lumigo.io" 23 | - name: Create VERSION commit 24 | run: | 25 | git add 'VERSION' 26 | git commit -m "Release version v$(< VERSION)" 27 | - name: Push VERSION commit 28 | uses: CasperWA/push-protected@v2 29 | with: 30 | token: ${{ secrets.TRIGGER_RELEASE_TOKEN }} 31 | branch: main 32 | -------------------------------------------------------------------------------- /telemetryproxy/src/processor/k8sdataenricherprocessor/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Lumigo 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package k8sdataenricherprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sdataenricherprocessor" 16 | 17 | import ( 18 | "github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig" 19 | ) 20 | 21 | type Config struct { 22 | k8sconfig.APIConfig `mapstructure:",squash"` 23 | } 24 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/internal/lumigo.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | operatorv1alpha1 "github.com/lumigo-io/lumigo-kubernetes-operator/api/v1alpha1" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | func NewLumigo(namespace, name, lumigoTokenSecretName, lumigoTokenSecretKey string, injectionEnabled bool, enableLogging bool) *operatorv1alpha1.Lumigo { 9 | return &operatorv1alpha1.Lumigo{ 10 | ObjectMeta: metav1.ObjectMeta{ 11 | Namespace: namespace, 12 | Name: name, 13 | Labels: map[string]string{}, 14 | }, 15 | Spec: operatorv1alpha1.LumigoSpec{ 16 | LumigoToken: operatorv1alpha1.Credentials{ 17 | SecretRef: operatorv1alpha1.KubernetesSecretRef{ 18 | Name: lumigoTokenSecretName, 19 | Key: lumigoTokenSecretKey, 20 | }, 21 | }, 22 | Tracing: operatorv1alpha1.TracingSpec{ 23 | Injection: operatorv1alpha1.InjectionSpec{ 24 | Enabled: &injectionEnabled, 25 | }, 26 | }, 27 | Logging: operatorv1alpha1.LoggingSpec{ 28 | Enabled: &enableLogging, 29 | }, 30 | }, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/bin/cdk.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import 'source-map-support/register'; 3 | import * as cdk from 'aws-cdk-lib'; 4 | import {EksOperatorTestCdkStack} from '../lib/cdk-stack'; 5 | 6 | const app = new cdk.App(); 7 | new EksOperatorTestCdkStack(app, 'EksOperatorTestCdkStack', { 8 | /* If you don't specify 'env', this stack will be environment-agnostic. 9 | * Account/Region-dependent features and context lookups will not work, 10 | * but a single synthesized template can be deployed anywhere. */ 11 | 12 | /* Uncomment the next line to specialize this stack for the AWS Account 13 | * and Region that are implied by the current CLI configuration. */ 14 | // env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION }, 15 | 16 | /* Uncomment the next line if you know exactly what Account and Region you 17 | * want to deploy the stack to. */ 18 | // env: { account: '123456789012', region: 'us-east-1' }, 19 | 20 | /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */ 21 | }); -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/testdata/config.yaml: -------------------------------------------------------------------------------- 1 | k8sobjects: 2 | objects: 3 | - name: pods 4 | mode: pull 5 | label_selector: environment in (production),tier in (frontend) 6 | field_selector: status.phase=Running 7 | - name: events 8 | mode: watch 9 | group: events.k8s.io 10 | namespaces: [default] 11 | exclude_watch_type: [DELETED] 12 | k8sobjects/pull_with_resource: 13 | objects: 14 | - name: pods 15 | mode: pull 16 | resource_version: "1" 17 | - name: events 18 | mode: pull 19 | k8sobjects/watch_with_resource: 20 | objects: 21 | - name: events 22 | mode: watch 23 | group: events.k8s.io 24 | namespaces: [default] 25 | - name: events 26 | mode: watch 27 | group: events.k8s.io 28 | namespaces: [default] 29 | resource_version: "2" 30 | k8sobjects/invalid_resource: 31 | objects: 32 | - name: fake_resource 33 | mode: watch 34 | k8sobjects/exclude_deleted_with_pull: 35 | objects: 36 | - name: events 37 | mode: pull 38 | exclude_watch_type: [DELETED] -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/resources/otlp-sink/config.yaml.tpl: -------------------------------------------------------------------------------- 1 | {{- $config := (datasource "config") -}} 2 | receivers: 3 | otlp: 4 | protocols: 5 | http: 6 | endpoint: "0.0.0.0:${OTLP_PORT}" 7 | 8 | exporters: 9 | debug: 10 | verbosity: detailed 11 | {{- if $config.lumigo_token }} 12 | otlphttp/lumigo: 13 | endpoint: {{ $config.lumigo_endpoint }} 14 | headers: 15 | Authorization: "LumigoToken {{ $config.lumigo_token }}" 16 | {{ end }} 17 | file/logs: 18 | path: ${LOGS_PATH} 19 | file/traces: 20 | path: ${TRACES_PATH} 21 | file/metrics: 22 | path: ${METRICS_PATH} 23 | service: 24 | pipelines: 25 | logs: 26 | receivers: 27 | - otlp 28 | exporters: 29 | - file/logs 30 | {{- if $config.lumigo_token }} 31 | - otlphttp/lumigo 32 | {{ end }} 33 | traces: 34 | receivers: 35 | - otlp 36 | exporters: 37 | - file/traces 38 | {{- if $config.lumigo_token }} 39 | - otlphttp/lumigo 40 | {{ end }} 41 | metrics: 42 | receivers: 43 | - otlp 44 | exporters: 45 | - file/metrics 46 | - debug -------------------------------------------------------------------------------- /.github/pull_request.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Fixes Issue 4 | 5 | 6 | 7 | 8 | 9 | ## Changes proposed 10 | 11 | 12 | 13 | 14 | 18 | 19 | ## Check List (Check all the boxes which are applicable) 20 | 21 | - [ ] My code follows the code style of this project. 22 | - [ ] My change requires a change to the documentation. 23 | - [ ] I have updated the documentation accordingly. 24 | - [ ] All new and existing tests passed. 25 | - [ ] This PR does not contain plagiarized content. 26 | - [ ] The title of my pull request is a short description of the requested changes. 27 | 28 | ## Screenshots 29 | 30 | 31 | 32 | ## Note to reviewers 33 | 34 | 35 | -------------------------------------------------------------------------------- /controller/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23 as builder 2 | ARG TARGETOS 3 | ARG TARGETARCH 4 | 5 | WORKDIR /workspace 6 | # Copy the go source 7 | COPY src/ . 8 | 9 | # cache deps before building and copying source so that we don't need to re-download as much 10 | # and so that source changes don't invalidate our downloaded layer 11 | RUN go mod download 12 | 13 | # Build 14 | # the GOARCH has not a default value to allow the binary be built according to the host where the command 15 | # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO 16 | # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, 17 | # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. 18 | RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go 19 | 20 | FROM alpine:latest 21 | 22 | # Be able to validate the TLS cert of the Lumigo SaaS endpoint 23 | RUN apk add bash procps 24 | 25 | WORKDIR / 26 | COPY --from=builder --chown=65532:65532 /workspace/manager . 27 | USER 65532:65532 28 | 29 | ENTRYPOINT ["/bin/bash"] 30 | CMD ["/lumigo/bin/entrypoint.sh"] 31 | -------------------------------------------------------------------------------- /watchdog/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23 as builder 2 | ARG TARGETOS 3 | ARG TARGETARCH 4 | 5 | WORKDIR /workspace 6 | # Copy the go source 7 | COPY src/ . 8 | 9 | # cache deps before building and copying source so that we don't need to re-download as much 10 | # and so that source changes don't invalidate our downloaded layer 11 | RUN go mod download 12 | 13 | # Build 14 | # the GOARCH has not a default value to allow the binary be built according to the host where the command 15 | # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO 16 | # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, 17 | # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. 18 | RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o watchdog main.go 19 | 20 | FROM alpine:latest 21 | 22 | # Be able to validate the TLS cert of the Lumigo SaaS endpoint 23 | RUN apk add bash procps 24 | 25 | WORKDIR / 26 | COPY --from=builder --chown=65532:65532 /workspace/watchdog . 27 | USER 65532:65532 28 | 29 | ENTRYPOINT ["/bin/bash"] 30 | CMD ["/lumigo/bin/entrypoint.sh"] 31 | -------------------------------------------------------------------------------- /controller/docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | readonly DEFAULT_MEMORY_LIMIT_MIB=4000 6 | readonly NO_MEMORY_LIMIT=9223372036854771712 7 | 8 | readonly CGROUPS_V1_MAX_MEMORY_PATH="/sys/fs/cgroup/memory/memory.limit_in_bytes" 9 | readonly CGROUPS_V2_MAX_MEMORY_PATH="/sys/fs/cgroup/memory.max" 10 | 11 | if [ -f "${CGROUPS_V1_MAX_MEMORY_PATH}" ]; then 12 | # cgroups v1 13 | memory_limit_bytes=$(<${CGROUPS_V1_MAX_MEMORY_PATH}) 14 | elif [ -f "${CGROUPS_V2_MAX_MEMORY_PATH}" ]; then 15 | # cgroups v2 16 | memory_limit_bytes=$(<${CGROUPS_V2_MAX_MEMORY_PATH}) 17 | fi 18 | 19 | if [ -n "${memory_limit_bytes}" ] && [ "${memory_limit_bytes}" != "${NO_MEMORY_LIMIT}" ]; then 20 | # Memory limits are set in the container 21 | memory_limit_mib=$(( ${memory_limit_bytes} / 1048576 )) 22 | fi 23 | 24 | if [ -n "${memory_limit_mib}" ]; then 25 | echo "Setting memory limits on the controller to ${memory_limit_mib} MiB" 26 | else 27 | echo "No memory limits found on the container; using the ${DEFAULT_MEMORY_LIMIT_MIB} MiB default" 28 | memory_limit_mib="${DEFAULT_MEMORY_LIMIT_MIB}" 29 | fi 30 | 31 | export GOMEMLIMIT="${memory_limit_mib}MiB" 32 | 33 | exec /manager "--config=${OTELCOL_CONFIG_FILE_PATH}" -------------------------------------------------------------------------------- /watchdog/docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | readonly DEFAULT_MEMORY_LIMIT_MIB=4000 6 | readonly NO_MEMORY_LIMIT=9223372036854771712 7 | 8 | readonly CGROUPS_V1_MAX_MEMORY_PATH="/sys/fs/cgroup/memory/memory.limit_in_bytes" 9 | readonly CGROUPS_V2_MAX_MEMORY_PATH="/sys/fs/cgroup/memory.max" 10 | 11 | if [ -f "${CGROUPS_V1_MAX_MEMORY_PATH}" ]; then 12 | # cgroups v1 13 | memory_limit_bytes=$(<${CGROUPS_V1_MAX_MEMORY_PATH}) 14 | elif [ -f "${CGROUPS_V2_MAX_MEMORY_PATH}" ]; then 15 | # cgroups v2 16 | memory_limit_bytes=$(<${CGROUPS_V2_MAX_MEMORY_PATH}) 17 | fi 18 | 19 | if [ -n "${memory_limit_bytes}" ] && [ "${memory_limit_bytes}" != "${NO_MEMORY_LIMIT}" ]; then 20 | # Memory limits are set in the container 21 | memory_limit_mib=$(( ${memory_limit_bytes} / 1048576 )) 22 | fi 23 | 24 | if [ -n "${memory_limit_mib}" ]; then 25 | echo "Setting memory limits on the watchdog to ${memory_limit_mib} MiB" 26 | else 27 | echo "No memory limits found on the container; using the ${DEFAULT_MEMORY_LIMIT_MIB} MiB default" 28 | memory_limit_mib="${DEFAULT_MEMORY_LIMIT_MIB}" 29 | fi 30 | 31 | export GOMEMLIMIT="${memory_limit_mib}MiB" 32 | 33 | exec /watchdog "--config=${OTELCOL_CONFIG_FILE_PATH}" 34 | -------------------------------------------------------------------------------- /telemetryproxy/src/internal/tools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/open-telemetry/opentelemetry-collector-contrib/internal/tools 2 | 3 | go 1.22.0 4 | 5 | toolchain go1.23.8 6 | 7 | require ( 8 | go.opentelemetry.io/collector/cmd/builder v0.116.0 9 | golang.org/x/tools v0.15.0 10 | ) 11 | 12 | require ( 13 | github.com/fsnotify/fsnotify v1.7.0 // indirect 14 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect 15 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 16 | github.com/knadh/koanf/maps v0.1.1 // indirect 17 | github.com/knadh/koanf/parsers/yaml v0.1.0 // indirect 18 | github.com/knadh/koanf/providers/env v1.0.0 // indirect 19 | github.com/knadh/koanf/providers/file v1.1.2 // indirect 20 | github.com/knadh/koanf/providers/fs v0.1.0 // indirect 21 | github.com/knadh/koanf/v2 v2.1.2 // indirect 22 | github.com/mitchellh/copystructure v1.2.0 // indirect 23 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 24 | github.com/spf13/cobra v1.8.1 // indirect 25 | github.com/spf13/pflag v1.0.5 // indirect 26 | go.uber.org/multierr v1.11.0 // indirect 27 | go.uber.org/zap v1.27.0 // indirect 28 | golang.org/x/mod v0.22.0 // indirect 29 | golang.org/x/sys v0.21.0 // indirect 30 | gopkg.in/yaml.v3 v3.0.1 // indirect 31 | ) 32 | 33 | retract v0.65.0 34 | -------------------------------------------------------------------------------- /telemetryproxy/src/internal/tools/tools.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019, OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build tools 16 | // +build tools 17 | 18 | package tools // import "github.com/lumigo-io/lumigo-kubernetes-operator/telemetryproxy/internal/tools" 19 | 20 | // This file follows the recommendation at 21 | // https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module 22 | // on how to pin tooling dependencies to a go.mod file. 23 | // This ensures that all systems use the same version of tools in addition to regular dependencies. 24 | 25 | import ( 26 | _ "go.opentelemetry.io/collector/cmd/builder" 27 | _ "golang.org/x/tools/cmd/goimports" 28 | ) 29 | -------------------------------------------------------------------------------- /watchdog/src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | stdlog "log" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | 9 | "github.com/lumigo-io/lumigo-kubernetes-operator/watchdog/config" 10 | "github.com/lumigo-io/lumigo-kubernetes-operator/watchdog/watchers" 11 | "golang.org/x/net/context" 12 | ) 13 | 14 | func main() { 15 | ctx, cancel := context.WithCancel(context.Background()) 16 | 17 | config := config.LoadConfig() 18 | watchdogContext, err := watchers.NewWatchdogK8sContext(ctx, config) 19 | 20 | if err != nil { 21 | stdlog.Fatalf("Failed to create K8s context: %v", err) 22 | } 23 | 24 | kubeWatcher, err := watchers.NewKubeWatcher(ctx, config, watchdogContext) 25 | if err != nil { 26 | stdlog.Fatalf("Failed to create KubeWatcher: %v", err) 27 | } 28 | 29 | topWatcher, err := watchers.NewTopWatcher(ctx, config, watchdogContext) 30 | if err != nil { 31 | stdlog.Fatalf("Failed to create TopWatcher: %v", err) 32 | } 33 | 34 | // Create a signal channel to handle graceful shutdown 35 | sigChan := make(chan os.Signal, 1) 36 | signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) 37 | 38 | go kubeWatcher.Watch(ctx) 39 | go topWatcher.Watch(ctx) 40 | 41 | // Wait for termination signal 42 | <-sigChan 43 | cancel() 44 | stdlog.Println("Watchdog received termination signal, shutting down") 45 | } 46 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/factory.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package k8sobjectsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sobjectsreceiver" 5 | 6 | import ( 7 | "context" 8 | 9 | "go.opentelemetry.io/collector/component" 10 | "go.opentelemetry.io/collector/consumer" 11 | "go.opentelemetry.io/collector/receiver" 12 | 13 | "github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig" 14 | "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sobjectsreceiver/internal/metadata" 15 | ) 16 | 17 | func NewFactory() receiver.Factory { 18 | return receiver.NewFactory( 19 | metadata.Type, 20 | createDefaultConfig, 21 | receiver.WithLogs( 22 | createLogsReceiver, 23 | metadata.LogsStability, 24 | ), 25 | ) 26 | } 27 | 28 | func createDefaultConfig() component.Config { 29 | return &Config{ 30 | APIConfig: k8sconfig.APIConfig{ 31 | AuthType: k8sconfig.AuthTypeServiceAccount, 32 | }, 33 | } 34 | } 35 | 36 | func createLogsReceiver( 37 | _ context.Context, 38 | params receiver.Settings, 39 | cfg component.Config, 40 | consumer consumer.Logs, 41 | ) (receiver.Logs, error) { 42 | rcfg := cfg.(*Config) 43 | return newReceiver(params, rcfg, consumer) 44 | } 45 | -------------------------------------------------------------------------------- /controller/src/controllers/internal/sorting/sorting_appsv1.go: -------------------------------------------------------------------------------- 1 | package sorting 2 | 3 | import ( 4 | appsv1 "k8s.io/api/apps/v1" 5 | ) 6 | 7 | type ByDaemonsetName []appsv1.DaemonSet 8 | 9 | func (s ByDaemonsetName) Len() int { 10 | return len(s) 11 | } 12 | func (s ByDaemonsetName) Swap(i, j int) { 13 | s[i], s[j] = s[j], s[i] 14 | } 15 | 16 | func (s ByDaemonsetName) Less(i, j int) bool { 17 | return s[i].Name < s[j].Name 18 | } 19 | 20 | type ByDeploymentName []appsv1.Deployment 21 | 22 | func (s ByDeploymentName) Len() int { 23 | return len(s) 24 | } 25 | func (s ByDeploymentName) Swap(i, j int) { 26 | s[i], s[j] = s[j], s[i] 27 | } 28 | 29 | func (s ByDeploymentName) Less(i, j int) bool { 30 | return s[i].Name < s[j].Name 31 | } 32 | 33 | type ByReplicaSetName []appsv1.ReplicaSet 34 | 35 | func (s ByReplicaSetName) Len() int { 36 | return len(s) 37 | } 38 | func (s ByReplicaSetName) Swap(i, j int) { 39 | s[i], s[j] = s[j], s[i] 40 | } 41 | 42 | func (s ByReplicaSetName) Less(i, j int) bool { 43 | return s[i].Name < s[j].Name 44 | } 45 | 46 | type ByStatefulSetName []appsv1.StatefulSet 47 | 48 | func (s ByStatefulSetName) Len() int { 49 | return len(s) 50 | } 51 | func (s ByStatefulSetName) Swap(i, j int) { 52 | s[i], s[j] = s[j], s[i] 53 | } 54 | 55 | func (s ByStatefulSetName) Less(i, j int) bool { 56 | return s[i].Name < s[j].Name 57 | } 58 | -------------------------------------------------------------------------------- /telemetryproxy/src/processor/k8sdataenricherprocessor/internal/relevant_gvk.go: -------------------------------------------------------------------------------- 1 | package internal // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sdataenricherprocessor/internal" 2 | 3 | import "k8s.io/apimachinery/pkg/runtime/schema" 4 | 5 | var ( 6 | V1Namespace = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"} 7 | V1Pod = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"} 8 | V1Event = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Event"} 9 | AppsV1DaemonSet = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "DaemonSet"} 10 | AppsV1Deployment = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"} 11 | AppsV1ReplicaSet = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "ReplicaSet"} 12 | AppsV1StatefulSet = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"} 13 | BatchV1CronJob = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"} 14 | BatchV1Job = schema.GroupVersionKind{Group: "batch", Version: "v1", Kind: "Job"} 15 | 16 | relevantOwnerReferenceGroupVersionKinds = []schema.GroupVersionKind{ 17 | V1Pod, 18 | AppsV1DaemonSet, 19 | AppsV1Deployment, 20 | AppsV1ReplicaSet, 21 | AppsV1StatefulSet, 22 | BatchV1CronJob, 23 | BatchV1Job, 24 | } 25 | ) 26 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/mock_log_consumer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package k8sobjectsreceiver 5 | 6 | import ( 7 | "context" 8 | "sync" 9 | 10 | "go.opentelemetry.io/collector/consumer" 11 | "go.opentelemetry.io/collector/pdata/plog" 12 | ) 13 | 14 | type mockLogConsumer struct { 15 | logs []plog.Logs 16 | count int 17 | lock sync.Mutex 18 | } 19 | 20 | func newMockLogConsumer() *mockLogConsumer { 21 | return &mockLogConsumer{ 22 | logs: make([]plog.Logs, 0), 23 | lock: sync.Mutex{}, 24 | } 25 | } 26 | 27 | func (m *mockLogConsumer) Capabilities() consumer.Capabilities { 28 | return consumer.Capabilities{ 29 | MutatesData: false, 30 | } 31 | } 32 | 33 | func (m *mockLogConsumer) ConsumeLogs(_ context.Context, ld plog.Logs) error { 34 | m.lock.Lock() 35 | defer m.lock.Unlock() 36 | m.logs = append(m.logs, ld) 37 | m.count += ld.LogRecordCount() 38 | return nil 39 | } 40 | 41 | func (m *mockLogConsumer) Count() int { 42 | m.lock.Lock() 43 | defer m.lock.Unlock() 44 | return m.count 45 | } 46 | 47 | func (m *mockLogConsumer) Logs() []plog.Logs { 48 | m.lock.Lock() 49 | defer m.lock.Unlock() 50 | logs := make([]plog.Logs, len(m.logs)) 51 | for i, log := range m.logs { 52 | l := plog.NewLogs() 53 | log.CopyTo(l) 54 | logs[i] = l 55 | } 56 | 57 | return logs 58 | } 59 | -------------------------------------------------------------------------------- /controller/src/api/v1alpha1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 Lumigo. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package v1alpha1 contains API Schema definitions for the operator v1alpha1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=operator.lumigo.io 20 | package v1alpha1 21 | 22 | import ( 23 | "k8s.io/apimachinery/pkg/runtime/schema" 24 | "sigs.k8s.io/controller-runtime/pkg/scheme" 25 | ) 26 | 27 | var ( 28 | // GroupVersion is group version used to register these objects 29 | GroupVersion = schema.GroupVersion{Group: "operator.lumigo.io", Version: "v1alpha1"} 30 | 31 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 32 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 33 | 34 | // AddToScheme adds the types in this group-version to the given scheme. 35 | AddToScheme = SchemeBuilder.AddToScheme 36 | ) 37 | -------------------------------------------------------------------------------- /config/scorecard/patches/olm.config.yaml: -------------------------------------------------------------------------------- 1 | - op: add 2 | path: /stages/0/tests/- 3 | value: 4 | entrypoint: 5 | - scorecard-test 6 | - olm-bundle-validation 7 | image: quay.io/operator-framework/scorecard-test:v1.26.0 8 | labels: 9 | suite: olm 10 | test: olm-bundle-validation-test 11 | - op: add 12 | path: /stages/0/tests/- 13 | value: 14 | entrypoint: 15 | - scorecard-test 16 | - olm-crds-have-validation 17 | image: quay.io/operator-framework/scorecard-test:v1.26.0 18 | labels: 19 | suite: olm 20 | test: olm-crds-have-validation-test 21 | - op: add 22 | path: /stages/0/tests/- 23 | value: 24 | entrypoint: 25 | - scorecard-test 26 | - olm-crds-have-resources 27 | image: quay.io/operator-framework/scorecard-test:v1.26.0 28 | labels: 29 | suite: olm 30 | test: olm-crds-have-resources-test 31 | - op: add 32 | path: /stages/0/tests/- 33 | value: 34 | entrypoint: 35 | - scorecard-test 36 | - olm-spec-descriptors 37 | image: quay.io/operator-framework/scorecard-test:v1.26.0 38 | labels: 39 | suite: olm 40 | test: olm-spec-descriptors-test 41 | - op: add 42 | path: /stages/0/tests/- 43 | value: 44 | entrypoint: 45 | - scorecard-test 46 | - olm-status-descriptors 47 | image: quay.io/operator-framework/scorecard-test:v1.26.0 48 | labels: 49 | suite: olm 50 | test: olm-status-descriptors-test 51 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Releasing the Lumigo Kubernetes Operator 2 | 3 | ## How to trigger a new release 4 | 5 | Trigger the [`Trigger release`](./.github/workflows/trigger-release.yml) workflow, which will push a commit to the `main` branch that increments linearly the version in the [VERSION](./VERSION) file. 6 | This, in turn, will trigger the release process (see next section). 7 | 8 | ## Release process 9 | 10 | The [build and release workflow](./.github/workflows/build-test-release.yml) will publish: 11 | 12 | 1. **Container images:** Build the [`lumigo-kubernetes-operator`](https://gallery.ecr.aws/lumigo/lumigo-kubernetes-operator) and [`lumigo-kubernetes-telemetry-proxy`](https://gallery.ecr.aws/lumigo/lumigo-kubernetes-telemetry-proxy) images, and push them with the new version as tag to the public Amazon ECR repositories. 13 | 1. **Helm chart defaults:** The new version is set as chart and app version in the [chart metadata](./deploy/helm/Chart.yaml); the new version is set as default tag in the [chart default values](./deploy/helm/values.yaml). 14 | 1. **Git tag and GitHub release:** Create a new GitHub release that has the new Helm chart tarball attached as artifact. 15 | 1. **Helm repository:** Update the index of the Helm repository hosted as GitHub Pages in the [`gh-pages` branch](https://github.com/lumigo-io/lumigo-kubernetes-operator/tree/gh-pages) will be automatically updated, pointing at the Helm chart tarball attached to the newly-created release. 16 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/proxy-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: {{ include "helm.fullname" . }}-proxy-role 5 | labels: 6 | {{- include "helm.labels" . | nindent 4 }} 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | rules: 11 | - apiGroups: 12 | - authentication.k8s.io 13 | resources: 14 | - tokenreviews 15 | verbs: 16 | - create 17 | - apiGroups: 18 | - authorization.k8s.io 19 | resources: 20 | - subjectaccessreviews 21 | verbs: 22 | - create 23 | - apiGroups: [""] 24 | resources: 25 | - nodes 26 | - nodes/proxy 27 | - nodes/stats 28 | - nodes/metrics 29 | - services 30 | - endpoints 31 | - pods 32 | verbs: ["get", "list", "watch"] 33 | 34 | --- 35 | apiVersion: rbac.authorization.k8s.io/v1 36 | kind: ClusterRoleBinding 37 | metadata: 38 | name: {{ include "helm.fullname" . }}-proxy-rolebinding 39 | labels: 40 | {{- include "helm.labels" . | nindent 4 }} 41 | app.kubernetes.io/component: kube-rbac-proxy 42 | app.kubernetes.io/created-by: lumigo 43 | app.kubernetes.io/part-of: lumigo 44 | roleRef: 45 | apiGroup: rbac.authorization.k8s.io 46 | kind: ClusterRole 47 | name: '{{ include "helm.fullname" . }}-proxy-role' 48 | subjects: 49 | - kind: ServiceAccount 50 | name: 'lumigo-kubernetes-operator' 51 | namespace: '{{ .Release.Namespace }}' -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/lumigooperatorheartbeatreceiver/README.md: -------------------------------------------------------------------------------- 1 | # Lumigo Operator Heartbeat Receiver 2 | 3 | | Status | | 4 | |--------------------------|------------| 5 | | Stability | [alpha] | 6 | | Supported pipeline types | logs | 7 | | Distributions | [lumigo-k8s] | 8 | 9 | This receiver sends downstream a heartbeat for one namespace every hour. 10 | The heartbeat contains the spec and status of all `lumigoes.operator.lumigo.io/v1alpha1.Lumigo` resources in the given namespace, formatted as JSON inside a log record. 11 | 12 | ### Configuration 13 | 14 | Example configuration: 15 | 16 | ``` 17 | receiver: 18 | lumigooperatorheartbeat: 19 | namespace: 20 | ``` 21 | 22 | This receiver will send the heartbeat for the `` namespace. 23 | Multiple receivers are needed to send heartbeats about multiple namespaces. 24 | The log records will be part of the `lumigo-operator.heartbeat` scope. 25 | 26 | ### Implementation 27 | 28 | The receiver has an internal ticker that, at its start and the top of every hour, retrieves from the Kubernetes API the spec and status of all `lumigoes.operator.lumigo.io/v1alpha1.Lumigo` resources in the given namespace, creates one log record for each, and sends it down the log pipeline. 29 | 30 | [alpha]: https://github.com/open-telemetry/opentelemetry-collector#alpha 31 | [lumigo-k8s]: https://github.com/lumigo-io/lumigo-kubernetes-operator/telemetryproxy 32 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/mock_discovery_client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package k8sobjectsreceiver 5 | 6 | import ( 7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 | "k8s.io/client-go/discovery" 9 | fakeDiscovery "k8s.io/client-go/discovery/fake" 10 | ) 11 | 12 | type MockDiscovery struct { 13 | fakeDiscovery.FakeDiscovery 14 | } 15 | 16 | func (c *MockDiscovery) ServerPreferredResources() ([]*metav1.APIResourceList, error) { 17 | return []*metav1.APIResourceList{ 18 | { 19 | GroupVersion: "v1", 20 | APIResources: []metav1.APIResource{ 21 | { 22 | Name: "pods", 23 | Kind: "Pod", 24 | }, 25 | { 26 | Name: "events", 27 | Kind: "Event", 28 | }, 29 | }, 30 | }, 31 | { 32 | GroupVersion: "events.k8s.io/v1", 33 | APIResources: []metav1.APIResource{ 34 | { 35 | Name: "events", 36 | Kind: "Event", 37 | }, 38 | }, 39 | }, 40 | { 41 | GroupVersion: "group1/v1", 42 | APIResources: []metav1.APIResource{ 43 | { 44 | Name: "myresources", 45 | Kind: "MyResource", 46 | }, 47 | }, 48 | }, 49 | { 50 | GroupVersion: "group2/v1", 51 | APIResources: []metav1.APIResource{ 52 | { 53 | Name: "myresources", 54 | Kind: "MyResource", 55 | }, 56 | }, 57 | }, 58 | }, nil 59 | } 60 | 61 | func getMockDiscoveryClient() (discovery.ServerResourcesInterface, error) { 62 | return &MockDiscovery{}, nil 63 | } 64 | -------------------------------------------------------------------------------- /watchdog/src/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "os" 5 | "strings" 6 | ) 7 | 8 | type Config struct { 9 | LumigoOperatorNamespace string 10 | LumigoOperatorVersion string 11 | LumigoMetricsEndpoint string 12 | LumigoLogsEndpoint string 13 | LumigoToken string 14 | TopWatcherInterval string 15 | Debug bool 16 | ClusterName string 17 | } 18 | 19 | func LoadConfig() *Config { 20 | return &Config{ 21 | LumigoOperatorNamespace: getEnvString("LUMIGO_OPERATOR_NAMESPACE", "lumigo-system"), 22 | LumigoOperatorVersion: getEnvString("LUMIGO_OPERATOR_VERSION", "unknown"), 23 | LumigoMetricsEndpoint: getEnvString("LUMIGO_METRICS_ENDPOINT", ""), 24 | LumigoLogsEndpoint: getEnvString("LUMIGO_LOGS_ENDPOINT", ""), 25 | TopWatcherInterval: getEnvString("LUMIGO_WATCHDOG_TOP_WATCHER_INTERVAL", "15s"), 26 | LumigoToken: getEnvString("LUMIGO_INFRA_METRICS_TOKEN", ""), 27 | Debug: getEnvBool("LUMIGO_DEBUG", false), 28 | ClusterName: getEnvString("KUBERNETES_CLUSTER_NAME", ""), 29 | } 30 | } 31 | 32 | func getEnvString(key string, defaultValue string) string { 33 | if value, exists := os.LookupEnv(key); exists { 34 | return value 35 | } 36 | return defaultValue 37 | } 38 | 39 | func getEnvBool(key string, defaultValue bool) bool { 40 | if value, exists := os.LookupEnv(key); exists { 41 | return strings.ToLower(value) == "true" 42 | } 43 | return defaultValue 44 | } 45 | -------------------------------------------------------------------------------- /config/certmanager/certificate.yaml: -------------------------------------------------------------------------------- 1 | # The following manifests contain a self-signed issuer CR and a certificate CR. 2 | # More document can be found at https://docs.cert-manager.io 3 | # WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes. 4 | apiVersion: cert-manager.io/v1 5 | kind: Issuer 6 | metadata: 7 | labels: 8 | app.kubernetes.io/name: issuer 9 | app.kubernetes.io/instance: selfsigned-issuer 10 | app.kubernetes.io/component: certificate 11 | app.kubernetes.io/created-by: lumigo 12 | app.kubernetes.io/part-of: lumigo 13 | app.kubernetes.io/managed-by: kustomize 14 | name: selfsigned-issuer 15 | namespace: system 16 | spec: 17 | selfSigned: {} 18 | --- 19 | apiVersion: cert-manager.io/v1 20 | kind: Certificate 21 | metadata: 22 | labels: 23 | app.kubernetes.io/name: certificate 24 | app.kubernetes.io/instance: serving-cert 25 | app.kubernetes.io/component: certificate 26 | app.kubernetes.io/created-by: lumigo 27 | app.kubernetes.io/part-of: lumigo 28 | app.kubernetes.io/managed-by: kustomize 29 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml 30 | namespace: system 31 | spec: 32 | dnsNames: 33 | - $(WEBHOOKS_SERVICE_NAME).$(WEBHOOKS_SERVICE_NAMESPACE).svc 34 | - $(WEBHOOKS_SERVICE_NAME).$(WEBHOOKS_SERVICE_NAMESPACE).svc.cluster.local 35 | issuerRef: 36 | kind: Issuer 37 | name: selfsigned-issuer 38 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize 39 | -------------------------------------------------------------------------------- /config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | creationTimestamp: null 6 | name: manager-role 7 | rules: 8 | - apiGroups: 9 | - operator.lumigo.io 10 | resources: 11 | - lumigoes 12 | verbs: 13 | - create 14 | - delete 15 | - get 16 | - list 17 | - patch 18 | - update 19 | - watch 20 | - apiGroups: 21 | - operator.lumigo.io 22 | resources: 23 | - lumigoes/finalizers 24 | verbs: 25 | - update 26 | - apiGroups: 27 | - operator.lumigo.io 28 | resources: 29 | - lumigoes/status 30 | verbs: 31 | - get 32 | - patch 33 | - update 34 | - apiGroups: 35 | - "" 36 | resources: 37 | - events 38 | verbs: 39 | - create 40 | - get 41 | - list 42 | - update 43 | - watch 44 | - apiGroups: 45 | - "" # Core API group 46 | resources: 47 | - namespaces 48 | - namespaces/status 49 | - nodes 50 | - nodes/spec 51 | - pods 52 | - pods/status 53 | - replicationcontrollers 54 | - replicationcontrollers/status 55 | - resourcequotas 56 | # The Lumigo operator will access only secrets that are referenced by a Lumigo CRD 57 | - secrets 58 | - services 59 | verbs: 60 | - get 61 | - list 62 | - watch 63 | - apiGroups: 64 | - apps 65 | resources: 66 | - daemonsets 67 | - deployments 68 | - replicasets 69 | - statefulsets 70 | verbs: 71 | - get 72 | - list 73 | - watch 74 | - update 75 | - apiGroups: 76 | - batch 77 | resources: 78 | - cronjobs 79 | - jobs 80 | verbs: 81 | - get 82 | - list 83 | - watch 84 | - update 85 | 86 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | lumigo-orb: &lumigo_orb_version lumigo/lumigo-orb@volatile 5 | 6 | workflows: 7 | test-deploy: 8 | jobs: 9 | - lumigo-orb/print_orb_versions: 10 | lumigo_orb_version: *lumigo_orb_version 11 | 12 | - lumigo-orb/is_environment_available: 13 | context: common 14 | filters: 15 | branches: 16 | ignore: 17 | - main 18 | 19 | - lumigo-orb/be-deploy: 20 | context: common 21 | save_project_folder: false 22 | requires: 23 | - lumigo-orb/is_environment_available 24 | 25 | - lumigo-orb/prep-it-resources: 26 | context: common 27 | venv_python_version: "3.9" 28 | requires: 29 | - lumigo-orb/is_environment_available 30 | 31 | - lumigo-orb/prep-k8s-and-operator: 32 | context: common 33 | requires: 34 | - lumigo-orb/is_environment_available 35 | 36 | - lumigo-orb/integration-test-parallel: 37 | context: common 38 | run_test_cleanup: false 39 | tests_max_parallel: 20 40 | requires: 41 | - lumigo-orb/be-deploy 42 | - lumigo-orb/prep-it-resources 43 | - lumigo-orb/prep-k8s-and-operator 44 | 45 | - lumigo-orb/integration-test-cleanup: 46 | name: post-test-cleanup 47 | context: common 48 | requires: 49 | - lumigo-orb/integration-test-parallel 50 | 51 | - lumigo-orb/workflow-completed-successfully: 52 | context: common 53 | requires: 54 | - lumigo-orb/integration-test-parallel 55 | -------------------------------------------------------------------------------- /kube-rbac-proxy/publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #################################################################################################################### 3 | # NOTE: The changes I made to the original publish script are: 4 | # 1. I changed the QUAY_PATH to be our docker repo. 5 | # 2. I changed the VERSION to be the version of the operator (and deleted the part that use to evaluate the version. 6 | #################################################################################################################### 7 | # exit immediately when a command fails 8 | set -e 9 | # only exit with zero if all commands of the pipeline exit successfully 10 | set -o pipefail 11 | # error on unset variables 12 | set -u 13 | # for debugging 14 | set -x 15 | 16 | QUAY_PATH="${DOCKER_REPO:-quay.io/brancz/kube-rbac-proxy}" 17 | CPU_ARCHS="amd64 arm64 arm ppc64le s390x" 18 | VERSION="${VERSION}" 19 | 20 | # build and push arch specific images 21 | for arch in ${CPU_ARCHS}; do 22 | VERSION="${VERSION}" DOCKER_REPO="${QUAY_PATH}" GOARCH="${arch}" make container 23 | docker push "${QUAY_PATH}:${VERSION}-${arch}" 24 | done 25 | 26 | # Create manifest to join all images under one virtual tag 27 | MANIFEST="docker manifest create -a ${QUAY_PATH}:${VERSION}" 28 | for arch in ${CPU_ARCHS}; do 29 | MANIFEST="${MANIFEST} ${QUAY_PATH}:${VERSION}-${arch}" 30 | done 31 | eval "${MANIFEST}" 32 | 33 | # Annotate to set which image is build for which CPU architecture 34 | for arch in ${CPU_ARCHS}; do 35 | docker manifest annotate --arch "${arch}" "${QUAY_PATH}:${VERSION}" "${QUAY_PATH}:${VERSION}-${arch}" 36 | done 37 | docker manifest push "${QUAY_PATH}:${VERSION}" 38 | -------------------------------------------------------------------------------- /config/webhooks/manifests.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: MutatingWebhookConfiguration 4 | metadata: 5 | creationTimestamp: null 6 | name: injector-webhook-configuration 7 | webhooks: 8 | - clientConfig: 9 | caBundle: Cg== 10 | service: 11 | name: webhooks-service 12 | namespace: system 13 | path: /v1alpha1/inject 14 | failurePolicy: Ignore 15 | admissionReviewVersions: 16 | - v1 17 | - v1beta1 18 | name: lumigoinjector.kb.io 19 | rules: 20 | - apiGroups: 21 | - apps 22 | apiVersions: 23 | - v1 24 | operations: 25 | - CREATE 26 | - UPDATE 27 | resources: 28 | - daemonsets 29 | - deployments 30 | - replicasets 31 | - statefulsets 32 | - apiGroups: 33 | - batch 34 | apiVersions: 35 | - v1 36 | operations: 37 | - CREATE 38 | - UPDATE 39 | resources: 40 | - cronjobs 41 | - jobs 42 | sideEffects: None 43 | timeoutSeconds: 5 44 | --- 45 | apiVersion: admissionregistration.k8s.io/v1 46 | kind: MutatingWebhookConfiguration 47 | metadata: 48 | creationTimestamp: null 49 | name: defaulter-webhook-configuration 50 | webhooks: 51 | - clientConfig: 52 | caBundle: Cg== 53 | service: 54 | name: webhooks-service 55 | namespace: system 56 | path: /v1alpha1/mutate 57 | failurePolicy: Fail 58 | admissionReviewVersions: 59 | - v1 60 | - v1beta1 61 | name: lumigodefaulter.kb.io 62 | rules: 63 | - apiGroups: 64 | - operator.lumigo.io 65 | apiVersions: 66 | - v1alpha1 67 | operations: 68 | - CREATE 69 | - UPDATE 70 | resources: 71 | - lumigoes 72 | sideEffects: None 73 | timeoutSeconds: 5 -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/factory_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package k8sobjectsreceiver 5 | 6 | import ( 7 | "context" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | "go.opentelemetry.io/collector/component" 13 | "go.opentelemetry.io/collector/consumer/consumertest" 14 | "go.opentelemetry.io/collector/receiver/receivertest" 15 | 16 | "github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig" 17 | ) 18 | 19 | func TestDefaultConfig(t *testing.T) { 20 | t.Parallel() 21 | cfg := createDefaultConfig() 22 | rCfg, ok := cfg.(*Config) 23 | require.True(t, ok) 24 | 25 | assert.Equal(t, &Config{ 26 | APIConfig: k8sconfig.APIConfig{ 27 | AuthType: k8sconfig.AuthTypeServiceAccount, 28 | }, 29 | }, rCfg) 30 | } 31 | 32 | func TestFactoryType(t *testing.T) { 33 | t.Parallel() 34 | assert.Equal(t, component.MustNewType("k8sobjects"), NewFactory().Type()) 35 | } 36 | 37 | func TestCreateReceiver(t *testing.T) { 38 | rCfg := createDefaultConfig().(*Config) 39 | 40 | // Fails with bad K8s Config. 41 | r, err := createLogsReceiver( 42 | context.Background(), receivertest.NewNopCreateSettings(), 43 | rCfg, consumertest.NewNop(), 44 | ) 45 | assert.Error(t, err) 46 | assert.Nil(t, r) 47 | 48 | // Override for test. 49 | rCfg.makeDynamicClient = newMockDynamicClient().getMockDynamicClient 50 | 51 | r, err = createLogsReceiver( 52 | context.Background(), 53 | receivertest.NewNopCreateSettings(), 54 | rCfg, consumertest.NewNop(), 55 | ) 56 | assert.NoError(t, err) 57 | assert.NotNil(t, r) 58 | } 59 | -------------------------------------------------------------------------------- /config/default/manager_auth_proxy_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch inject a sidecar container which is a HTTP proxy for the 2 | # controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: controller-manager 7 | namespace: system 8 | spec: 9 | template: 10 | spec: 11 | affinity: 12 | nodeAffinity: 13 | requiredDuringSchedulingIgnoredDuringExecution: 14 | nodeSelectorTerms: 15 | - matchExpressions: 16 | - key: kubernetes.io/arch 17 | operator: In 18 | values: 19 | - amd64 20 | - arm64 21 | - key: kubernetes.io/os 22 | operator: In 23 | values: 24 | - linux 25 | containers: 26 | - name: kube-rbac-proxy 27 | securityContext: 28 | allowPrivilegeEscalation: false 29 | capabilities: 30 | drop: 31 | - "ALL" 32 | image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.0 33 | args: 34 | - "--secure-listen-address=0.0.0.0:8443" 35 | - "--upstream=http://127.0.0.1:8080/" 36 | - "--logtostderr=true" 37 | - "--v=0" 38 | ports: 39 | - containerPort: 8443 40 | protocol: TCP 41 | name: https 42 | resources: 43 | limits: 44 | cpu: 500m 45 | memory: 128Mi 46 | requests: 47 | cpu: 5m 48 | memory: 64Mi 49 | - name: manager 50 | args: 51 | - "--health-probe-bind-address=:8081" 52 | - "--metrics-bind-address=127.0.0.1:8080" 53 | - "--leader-elect" 54 | -------------------------------------------------------------------------------- /telemetryproxy/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the telemetry-proxy from sources 2 | FROM golang:1.23-alpine AS telemetry-proxy-builder 3 | 4 | ARG version='dev' 5 | ARG TARGETOS 6 | ARG TARGETARCH 7 | 8 | ENV VERSION=${version} 9 | 10 | RUN apk add --update make git 11 | 12 | ADD ./src /src 13 | WORKDIR /src 14 | 15 | RUN make VERSION=${VERSION} GOOS=${TARGETOS} GOARCH=${TARGETARCH} OTELCONTRIBCOL_FILENAME=otelcontribcol otelcontribcolbuilder 16 | 17 | # We need to chmod files to fit the expected uid and gid 18 | # at runtime. Since we do not want to depend on buildkit, 19 | # which has the handy `ADD --chown=:` facility, 20 | # we rely on a helper image to avoid ugliness in unnecessary 21 | # layers in the final image 22 | FROM alpine:latest AS chmod-helper 23 | 24 | ADD ./docker/etc/config.yaml.tpl /lumigo/etc/otelcol-config.yaml.tpl 25 | ADD ./docker/etc/events-config.yaml.tpl /lumigo/etc/otelcol-events-config.yaml.tpl 26 | ADD ./docker/etc/common-config.yaml /lumigo/etc/otelcol-common-config.yaml 27 | RUN chown -R 1234:1234 /lumigo/etc/otelcol-config.yaml.tpl 28 | RUN chown -R 1234:1234 /lumigo/etc/otelcol-events-config.yaml.tpl 29 | 30 | COPY --from=telemetry-proxy-builder /src/dist/otelcontribcol /lumigo/bin/otelcol 31 | ADD ./docker/*.sh /lumigo/bin/ 32 | 33 | RUN chmod -R u+x /lumigo/bin/* 34 | RUN chown -R 1234:1234 /lumigo/bin/* 35 | 36 | FROM alpine:latest 37 | 38 | # Be able to validate the TLS cert of the Lumigo SaaS endpoint 39 | RUN apk add ca-certificates 40 | 41 | RUN apk add bash procps 42 | # `apk add gomplate` installs a version with a vulenrability of CVE-2024-34158. 43 | # Once the package is updated, we can install it via `apk` 44 | COPY --from=hairyhenderson/gomplate:latest /gomplate /bin/gomplate 45 | 46 | COPY --from=chmod-helper /lumigo /lumigo 47 | 48 | ENTRYPOINT ["/bin/bash"] 49 | CMD ["/lumigo/bin/entrypoint.sh"] -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/internal/context.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | type ContextKey string 4 | 5 | var ( 6 | ContextKeyRunId = ContextKey("run-id") 7 | ContextKeyKubernetesClusterName = ContextKey("kubernetes/cluster/name") 8 | ContextKeyOtlpSinkConfigPath = ContextKey("otlp-sink/config") 9 | ContextKeyOtlpSinkDataPath = ContextKey("otlp-sink/data") 10 | ContextKeyLumigoEndpoint = ContextKey("lumigo/endpoint") 11 | ContextKeyLumigoOperatorDebug = ContextKey("lumigo/debug") 12 | ContextKeyLumigoToken = ContextKey("lumigo/token") 13 | ContextKeyOperatorControllerImage = ContextKey("lumigo/operator/images/controller") 14 | ContextKeyOperatorTelemetryProxyImage = ContextKey("lumigo/operator/images/proxy") 15 | ContextKeyOperatorWatchdogImage = ContextKey("lumigo/operator/images/watchdog") 16 | ContextKeySendDataToLumigo = ContextKey("lumigo/upstream/send_data") 17 | ContextTestAppJsClientImageName = ContextKey("test-apps/js/client/image/name") 18 | ContextTestAppJsServerImageName = ContextKey("test-apps/js/server/image/name") 19 | ContextTestAppPythonImageName = ContextKey("test-apps/python/image/name") 20 | ContextTestAppBusyboxIncludedContainerNamePrefix = ContextKey("test-apps/busybox/included-container/name") 21 | ContextTestAppBusyboxExcludedContainerNamePrefix = ContextKey("test-apps/busybox/excluded-container/name") 22 | ContextTestAppNamespacePrefix = ContextKey("test-apps/namespace/prefix") 23 | ContextQuickstartNamespace = ContextKey("test-apps/namespace/quickstart") 24 | ) 25 | 26 | func (c ContextKey) String() string { 27 | return "ctx.key:" + string(c) 28 | } 29 | -------------------------------------------------------------------------------- /tools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lumigo-io/lumigo-kubernetes-operator/tools 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.8 6 | 7 | require ( 8 | github.com/tcnksm/ghr v0.16.0 9 | go.opentelemetry.io/collector/cmd/builder v0.90.0 10 | golang.org/x/tools v0.15.0 11 | ) 12 | 13 | require ( 14 | github.com/Songmu/retry v0.1.0 // indirect 15 | github.com/fsnotify/fsnotify v1.7.0 // indirect 16 | github.com/google/go-cmp v0.6.0 // indirect 17 | github.com/google/go-github v17.0.0+incompatible // indirect 18 | github.com/google/go-github/v47 v47.1.0 // indirect 19 | github.com/google/go-querystring v1.1.0 // indirect 20 | github.com/hashicorp/go-version v1.6.0 // indirect 21 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 22 | github.com/knadh/koanf v1.5.0 // indirect 23 | github.com/knadh/koanf/v2 v2.0.1 // indirect 24 | github.com/mattn/go-colorable v0.1.13 // indirect 25 | github.com/mattn/go-isatty v0.0.20 // indirect 26 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect 27 | github.com/mitchellh/copystructure v1.2.0 // indirect 28 | github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect 29 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 30 | github.com/onsi/gomega v1.30.0 // indirect 31 | github.com/pkg/errors v0.9.1 // indirect 32 | github.com/spf13/cobra v1.8.0 // indirect 33 | github.com/spf13/pflag v1.0.5 // indirect 34 | github.com/tcnksm/go-gitconfig v0.1.2 // indirect 35 | github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e // indirect 36 | go.uber.org/multierr v1.11.0 // indirect 37 | go.uber.org/zap v1.26.0 // indirect 38 | golang.org/x/crypto v0.36.0 // indirect 39 | golang.org/x/mod v0.14.0 // indirect 40 | golang.org/x/net v0.38.0 // indirect 41 | golang.org/x/oauth2 v0.27.0 // indirect 42 | golang.org/x/sync v0.5.0 // indirect 43 | golang.org/x/sys v0.31.0 // indirect 44 | gopkg.in/yaml.v3 v3.0.1 // indirect 45 | ) 46 | -------------------------------------------------------------------------------- /docs/ecr-public-gallery/LumigoTelemetryProxyImage/About.md: -------------------------------------------------------------------------------- 1 | # Lumigo Kubernetes operator: Telemetry-Proxy image 2 | 3 | This image is part of the [Lumigo Kubernetes Operator](https://docs.lumigo.io/docs/lumigo-kubernetes-operator). 4 | The Lumigo Kubernetes operator is best way to monitor Kubernetes applications with Lumigo. 5 | 6 | Using the Lumigo Kubernetes operator is as simple as: 7 | 8 | 1. Install the Lumigo Kubernetes operator on your cluster via Helm 9 | 10 | ``` 11 | helm repo add lumigo https://lumigo-io.github.io/lumigo-kubernetes-operator 12 | helm install lumigo lumigo/lumigo-operator --namespace lumigo-system --create-namespace 13 | ``` 14 | 15 | 2. In the Kubernetes namespaces with applications you want to trace, create a Kubernetes secret containing the Lumigo Token, and a Lumigo resource pointing to it: 16 | 17 | ``` 18 | apiVersion: v1 19 | kind: Secret 20 | metadata: 21 | name: lumigo-credentials 22 | stringData: 23 | # Kubectl won't allow you to deploy this dangling anchor. 24 | # Get the actual value from Lumigo following this documentation: https://docs.lumigo.io/docs/lumigo-tokens 25 | token: *lumigo-token # Example: t_123456789012345678901 26 | --- 27 | apiVersion: operator.lumigo.io/v1alpha1 28 | kind: Lumigo 29 | metadata: 30 | labels: 31 | app.kubernetes.io/name: lumigo 32 | app.kubernetes.io/instance: lumigo 33 | app.kubernetes.io/part-of: lumigo-operator 34 | name: lumigo 35 | spec: 36 | lumigoToken: 37 | secretRef: 38 | name: lumigo-credentials # This must match the name of the secret; the secret must be in the same namespace as this Lumigo custom resource 39 | key: token # This must match the key in the Kubernetes secret 40 | ``` 41 | 42 | The Lumigo Kubernetes operator will update your deployments, daemonsets, replicasets, statefulsets, cronjobs and jobs to be traced with the Lumigo OpenTelemetry Distro for Node.js and Lumigo OpenTelemetry Distro for Python. 43 | 44 | More detailed instructions are available in the Lumigo Kubernetes operator repository on GitHub. 45 | -------------------------------------------------------------------------------- /docs/ecr-public-gallery/LumigoKubernetesOperatorImage/About.md: -------------------------------------------------------------------------------- 1 | # Lumigo Kubernetes operator: Kubernetes-Operator image 2 | 3 | This image is part of the [Lumigo Kubernetes Operator](https://docs.lumigo.io/docs/lumigo-kubernetes-operator). 4 | The Lumigo Kubernetes operator is best way to monitor Kubernetes applications with Lumigo. 5 | 6 | Using the Lumigo Kubernetes operator is as simple as: 7 | 8 | 1. Install the Lumigo Kubernetes operator on your cluster via Helm 9 | 10 | ``` 11 | helm repo add lumigo https://lumigo-io.github.io/lumigo-kubernetes-operator 12 | helm install lumigo lumigo/lumigo-operator --namespace lumigo-system --create-namespace 13 | ``` 14 | 15 | 2. In the Kubernetes namespaces with applications you want to trace, create a Kubernetes secret containing the Lumigo Token, and a Lumigo resource pointing to it: 16 | 17 | ``` 18 | apiVersion: v1 19 | kind: Secret 20 | metadata: 21 | name: lumigo-credentials 22 | stringData: 23 | # Kubectl won't allow you to deploy this dangling anchor. 24 | # Get the actual value from Lumigo following this documentation: https://docs.lumigo.io/docs/lumigo-tokens 25 | token: *lumigo-token # Example: t_123456789012345678901 26 | --- 27 | apiVersion: operator.lumigo.io/v1alpha1 28 | kind: Lumigo 29 | metadata: 30 | labels: 31 | app.kubernetes.io/name: lumigo 32 | app.kubernetes.io/instance: lumigo 33 | app.kubernetes.io/part-of: lumigo-operator 34 | name: lumigo 35 | spec: 36 | lumigoToken: 37 | secretRef: 38 | name: lumigo-credentials # This must match the name of the secret; the secret must be in the same namespace as this Lumigo custom resource 39 | key: token # This must match the key in the Kubernetes secret 40 | ``` 41 | 42 | The Lumigo Kubernetes operator will update your deployments, daemonsets, replicasets, statefulsets, cronjobs and jobs to be traced with the Lumigo OpenTelemetry Distro for Node.js and Lumigo OpenTelemetry Distro for Python. 43 | 44 | More detailed instructions are available in the Lumigo Kubernetes operator repository on GitHub. 45 | -------------------------------------------------------------------------------- /watchdog/src/watchers/utils.go: -------------------------------------------------------------------------------- 1 | package watchers 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" 8 | "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" 9 | ) 10 | 11 | func normalizeEndpoint(originalEndpoint string, expectedSuffix string) (string, bool) { 12 | endpoint := originalEndpoint 13 | isInsecure := strings.HasPrefix(endpoint, "http://") 14 | // Remove http:// or https:// prefix if it exists, as the exporter will add it 15 | if len(endpoint) >= 7 && endpoint[:7] == "http://" { 16 | endpoint = endpoint[7:] 17 | } else if len(endpoint) >= 8 && endpoint[:8] == "https://" { 18 | endpoint = endpoint[8:] 19 | } 20 | 21 | // Remove trailing slash if present 22 | if len(endpoint) > 0 && endpoint[len(endpoint)-1] == '/' { 23 | endpoint = endpoint[:len(endpoint)-1] 24 | } 25 | 26 | // To remove /v1/metrics or /v1/logs if provided, as it's already added by the exporter 27 | if len(endpoint) > len(expectedSuffix) && endpoint[len(endpoint)-len(expectedSuffix):] == expectedSuffix { 28 | endpoint = endpoint[:len(endpoint)-len(expectedSuffix)] 29 | } 30 | 31 | return endpoint, isInsecure 32 | } 33 | 34 | func LogsExporterConfigOptions(originalEndpoint string, lumigoToken string) *[]otlploghttp.Option { 35 | endpoint, isInsecure := normalizeEndpoint(originalEndpoint, "/v1/logs") 36 | 37 | opts := []otlploghttp.Option{ 38 | otlploghttp.WithEndpoint(endpoint), 39 | otlploghttp.WithHeaders(map[string]string{ 40 | "Authorization": fmt.Sprintf("LumigoToken %s", lumigoToken), 41 | }), 42 | } 43 | 44 | if isInsecure { 45 | opts = append(opts, otlploghttp.WithInsecure()) 46 | } 47 | 48 | return &opts 49 | } 50 | 51 | func MetricsExporterConfigOptions(originalEndpoint string, lumigoToken string) *[]otlpmetrichttp.Option { 52 | endpoint, isInsecure := normalizeEndpoint(originalEndpoint, "/v1/metrics") 53 | 54 | opts := []otlpmetrichttp.Option{ 55 | otlpmetrichttp.WithEndpoint(endpoint), 56 | otlpmetrichttp.WithHeaders(map[string]string{ 57 | "Authorization": fmt.Sprintf("LumigoToken %s", lumigoToken), 58 | }), 59 | } 60 | 61 | if isInsecure { 62 | opts = append(opts, otlpmetrichttp.WithInsecure()) 63 | } 64 | 65 | return &opts 66 | } 67 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/mock_dynamic_client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package k8sobjectsreceiver 5 | 6 | import ( 7 | "context" 8 | 9 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 11 | "k8s.io/apimachinery/pkg/runtime" 12 | "k8s.io/apimachinery/pkg/runtime/schema" 13 | "k8s.io/client-go/dynamic" 14 | "k8s.io/client-go/dynamic/fake" 15 | ) 16 | 17 | type mockDynamicClient struct { 18 | client dynamic.Interface 19 | } 20 | 21 | func newMockDynamicClient() mockDynamicClient { 22 | scheme := runtime.NewScheme() 23 | objs := []runtime.Object{} 24 | 25 | gvrToListKind := map[schema.GroupVersionResource]string{ 26 | {Group: "", Version: "v1", Resource: "pods"}: "PodList", 27 | } 28 | 29 | fakeClient := fake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind, objs...) 30 | return mockDynamicClient{ 31 | client: fakeClient, 32 | } 33 | 34 | } 35 | 36 | func (c mockDynamicClient) getMockDynamicClient() (dynamic.Interface, error) { 37 | return c.client, nil 38 | } 39 | 40 | func (c mockDynamicClient) createPods(objects ...*unstructured.Unstructured) { 41 | pods := c.client.Resource(schema.GroupVersionResource{ 42 | Version: "v1", 43 | Resource: "pods", 44 | }) 45 | for _, pod := range objects { 46 | _, _ = pods.Namespace(pod.GetNamespace()).Create(context.Background(), pod, v1.CreateOptions{}) 47 | } 48 | } 49 | 50 | func (c mockDynamicClient) deletePods(objects ...*unstructured.Unstructured) { 51 | pods := c.client.Resource(schema.GroupVersionResource{ 52 | Version: "v1", 53 | Resource: "pods", 54 | }) 55 | for _, pod := range objects { 56 | _ = pods.Namespace(pod.GetNamespace()).Delete(context.Background(), pod.GetName(), v1.DeleteOptions{}) 57 | } 58 | } 59 | 60 | func generatePod(name, namespace string, labels map[string]any, resourceVersion string) *unstructured.Unstructured { 61 | pod := unstructured.Unstructured{ 62 | Object: map[string]any{ 63 | "apiVersion": "v1", 64 | "kind": "Pods", 65 | "metadata": map[string]any{ 66 | "namespace": namespace, 67 | "name": name, 68 | "labels": labels, 69 | }, 70 | }, 71 | } 72 | 73 | pod.SetResourceVersion(resourceVersion) 74 | return &pod 75 | } 76 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/uninstallation/uninstall-hook.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: {{ include "helm.fullname" . }}-uninstall-hook 5 | labels: 6 | {{- include "helm.labels" . | nindent 4 }} 7 | app.kubernetes.io/component: manager 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | control-plane: controller-manager 11 | lumigo.auto-trace: 'false' # We do not need the operator to inject itself 12 | annotations: 13 | helm.sh/hook: pre-delete 14 | {{- if not .Values.debug.enabled }} 15 | helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded # we skip hook-failed so that we can look up logs if it fails 16 | {{- end }} 17 | 18 | spec: 19 | completions: 1 20 | backoffLimit: 2 21 | template: 22 | metadata: 23 | name: "{{ .Release.Name }}" 24 | labels: 25 | {{- include "helm.selectorLabels" . | nindent 8 }} 26 | lumigo.auto-trace: 'false' # We do not need the operator to inject itself 27 | control-plane: controller-manager 28 | spec: 29 | restartPolicy: Never 30 | activeDeadlineSeconds: 120 # Unfortunately, as of v3.11, Helm does not expose to templates its own timeout 31 | containers: 32 | - name: uninstall-hook 33 | image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }} 34 | command: ["/manager", "--uninstall"] 35 | securityContext: 36 | allowPrivilegeEscalation: false 37 | capabilities: 38 | drop: 39 | - ALL 40 | readOnlyRootFilesystem: true 41 | runAsNonRoot: true 42 | securityContext: 43 | runAsNonRoot: true 44 | fsGroup: 1234 45 | serviceAccountName: lumigo-kubernetes-operator 46 | {{- if or .Values.tolerations.uninstallHook .Values.tolerations.global }} 47 | tolerations: 48 | {{- toYaml (.Values.tolerations.uninstallHook | default .Values.tolerations.global) | nindent 6 }} 49 | {{- end }} 50 | {{- if or .Values.nodeSelector.uninstallHook .Values.nodeSelector.global }} 51 | nodeSelector: 52 | {{- toYaml (.Values.nodeSelector.uninstallHook | default .Values.nodeSelector.global) | nindent 8 }} 53 | {{- end }} -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/client/app.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | const { init } = require('@lumigo/opentelemetry'); 4 | const { SpanStatusCode, trace } = require('@opentelemetry/api'); 5 | const winston = require('winston'); 6 | 7 | if (!process.env.TARGET_URL) { 8 | throw new Error("The required environment variable 'TARGET_URL' is not set") 9 | } 10 | 11 | (async () => { 12 | const { tracerProvider } = await init; 13 | const tracer = trace.getTracer(__filename) 14 | const logger = winston.createLogger({ 15 | transports: [new winston.transports.Console()], 16 | level: 'info' 17 | }); 18 | logger.info('Starting batch job...'); 19 | await tracer.startActiveSpan('batch', async (rootSpan) => { 20 | try { 21 | const res = await axios.post(`${process.env.TARGET_URL}/api/checkout`, { 22 | "reference": "Order1234567", 23 | "line_items": [ 24 | { 25 | "name": "60,000 mile maintenance", 26 | "quantity": "1", 27 | "base_price_money": { 28 | "amount": 30000, 29 | "currency": "USD" 30 | }, 31 | "note": "1st line item note" 32 | }, 33 | { 34 | "name": "Tire rotation and balancing", 35 | "quantity": "1", 36 | "base_price_money": { 37 | "amount": 15000, 38 | "currency": "USD" 39 | } 40 | }, 41 | { 42 | "name": "Wiper fluid replacement", 43 | "quantity": "1", 44 | "base_price_money": { 45 | "amount": 1900, 46 | "currency": "USD" 47 | } 48 | }, 49 | { 50 | "name": "Oil change", 51 | "quantity": "1", 52 | "base_price_money": { 53 | "amount": 2000, 54 | "currency": "USD" 55 | } 56 | } 57 | ] 58 | }); 59 | console.log(`Request succesful: ${res}`); 60 | } catch (err) { 61 | rootSpan.recordException(err); 62 | rootSpan.setStatus({ 63 | code: SpanStatusCode.ERROR, 64 | }); 65 | throw err; 66 | } finally { 67 | try { 68 | rootSpan.end(); 69 | } finally { 70 | await tracerProvider.shutdown(); 71 | } 72 | } 73 | }); 74 | })(); 75 | -------------------------------------------------------------------------------- /config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Adds namespace to all resources. 2 | namespace: lumigo-system 3 | 4 | # Value of this field is prepended to the 5 | # names of all resources, e.g. a deployment named 6 | # "wordpress" becomes "alices-wordpress". 7 | # Note that it should also match with the prefix (text before '-') of the namespace 8 | # field above. 9 | namePrefix: lumigo- 10 | 11 | # Labels to add to all resources and selectors. 12 | #commonLabels: 13 | # someName: someValue 14 | 15 | bases: 16 | - ../crd 17 | - ../rbac 18 | - ../manager 19 | - ../webhooks 20 | - ../certmanager 21 | - ../telemetry-proxy 22 | - ../watchdog 23 | # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. 24 | #- ../prometheus 25 | 26 | patchesStrategicMerge: 27 | # Protect the /metrics endpoint by putting it behind auth. 28 | # If you want your controller-manager to expose the /metrics 29 | # endpoint w/o any authn/z, please comment the following line. 30 | - manager_auth_proxy_patch.yaml 31 | - manager_webhook_patch.yaml 32 | - webhooks_cainjection_patch.yaml 33 | 34 | # the following config is for teaching kustomize how to do var substitution 35 | vars: 36 | - name: CERTIFICATE_NAMESPACE # namespace of the certificate CR 37 | objref: 38 | kind: Certificate 39 | group: cert-manager.io 40 | version: v1 41 | name: serving-cert # this name should match the one in certificate.yaml 42 | fieldref: 43 | fieldpath: metadata.namespace 44 | - name: CERTIFICATE_NAME 45 | objref: 46 | kind: Certificate 47 | group: cert-manager.io 48 | version: v1 49 | name: serving-cert # this name should match the one in certificate.yaml 50 | - name: WEBHOOKS_SERVICE_NAMESPACE # namespace of the service 51 | objref: 52 | kind: Service 53 | version: v1 54 | name: webhooks-service 55 | fieldref: 56 | fieldpath: metadata.namespace 57 | - name: WEBHOOKS_SERVICE_NAME 58 | objref: 59 | kind: Service 60 | version: v1 61 | name: webhooks-service 62 | - name: TELEMETRY_PROXY_SERVICE_NAMESPACE # namespace of the service 63 | objref: 64 | kind: Service 65 | version: v1 66 | name: telemetry-proxy-service 67 | fieldref: 68 | fieldpath: metadata.namespace 69 | - name: TELEMETRY_PROXY_SERVICE_NAME 70 | objref: 71 | kind: Service 72 | version: v1 73 | name: telemetry-proxy-service 74 | -------------------------------------------------------------------------------- /controller/src/api/v1alpha1/lumigo_events.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | "fmt" 5 | 6 | corev1 "k8s.io/api/core/v1" 7 | runtime "k8s.io/apimachinery/pkg/runtime" 8 | "k8s.io/client-go/tools/record" 9 | ) 10 | 11 | func RecordAddedInstrumentationEvent(eventRecorder record.EventRecorder, resource runtime.Object, trigger string) { 12 | eventRecorder.Event( 13 | resource, 14 | corev1.EventTypeNormal, 15 | string(LumigoEventReasonAddedInstrumentation), 16 | fmt.Sprintf("Adding Lumigo instrumentation (trigger: %s)", trigger), 17 | ) 18 | } 19 | 20 | func RecordRemovedInstrumentationEvent(eventRecorder record.EventRecorder, resource runtime.Object, trigger string) { 21 | eventRecorder.Event( 22 | resource, 23 | corev1.EventTypeNormal, 24 | string(LumigoEventReasonRemovedInstrumentation), 25 | fmt.Sprintf("Removing Lumigo instrumentation (trigger: %s)", trigger), 26 | ) 27 | } 28 | 29 | func RecordUpdatedInstrumentationEvent(eventRecorder record.EventRecorder, resource runtime.Object, trigger string) { 30 | eventRecorder.Event( 31 | resource, 32 | corev1.EventTypeNormal, 33 | string(LumigoEventReasonUpdatedInstrumentation), 34 | fmt.Sprintf("Updating Lumigo instrumentation (trigger: %s)", trigger), 35 | ) 36 | } 37 | 38 | func RecordCannotAddInstrumentationEvent(eventRecorder record.EventRecorder, resource runtime.Object, trigger string, err error) { 39 | eventRecorder.Event( 40 | resource, 41 | corev1.EventTypeWarning, 42 | string(LumigoEventReasonCannotAddInstrumentation), 43 | fmt.Sprintf("Cannot add Lumigo instrumentation (trigger: %s): %s", trigger, err.Error()), 44 | ) 45 | } 46 | 47 | func RecordCannotRemoveInstrumentationEvent(eventRecorder record.EventRecorder, resource runtime.Object, trigger string, err error) { 48 | eventRecorder.Event( 49 | resource, 50 | corev1.EventTypeWarning, 51 | string(LumigoEventReasonCannotRemoveInstrumentation), 52 | fmt.Sprintf("Cannot remove Lumigo instrumentation (trigger: %s): %s", trigger, err.Error()), 53 | ) 54 | } 55 | 56 | func RecordCannotUpdateInstrumentationEvent(eventRecorder record.EventRecorder, resource runtime.Object, trigger string, err error) { 57 | eventRecorder.Event( 58 | resource, 59 | corev1.EventTypeWarning, 60 | string(LumigoEventReasonCannotUpdateInstrumentation), 61 | fmt.Sprintf("Cannot update Lumigo instrumentation (trigger: %s): %s", trigger, err.Error()), 62 | ) 63 | } 64 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/manager-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: {{ include "helm.fullname" . }}-manager-role 5 | labels: 6 | {{- include "helm.labels" . | nindent 4 }} 7 | rules: 8 | - apiGroups: 9 | - operator.lumigo.io 10 | resources: 11 | - lumigoes 12 | verbs: 13 | - create 14 | - delete 15 | - get 16 | - list 17 | - patch 18 | - update 19 | - watch 20 | - apiGroups: 21 | - operator.lumigo.io 22 | resources: 23 | - lumigoes/finalizers 24 | verbs: 25 | - update 26 | - apiGroups: 27 | - operator.lumigo.io 28 | resources: 29 | - lumigoes/status 30 | verbs: 31 | - get 32 | - patch 33 | - update 34 | - apiGroups: 35 | - "" 36 | resources: 37 | - events 38 | verbs: 39 | - create 40 | - get 41 | - list 42 | - update 43 | - watch 44 | - apiGroups: 45 | - "" 46 | resources: 47 | - namespaces 48 | - namespaces/status 49 | - nodes 50 | - nodes/spec 51 | - pods 52 | - pods/status 53 | - replicationcontrollers 54 | - replicationcontrollers/status 55 | - resourcequotas 56 | - secrets 57 | - services 58 | verbs: 59 | - get 60 | - list 61 | - watch 62 | - apiGroups: 63 | - apps 64 | resources: 65 | - daemonsets 66 | - deployments 67 | - replicasets 68 | - statefulsets 69 | verbs: 70 | - get 71 | - list 72 | - watch 73 | - update 74 | - apiGroups: 75 | - batch 76 | resources: 77 | - cronjobs 78 | - jobs 79 | verbs: 80 | - get 81 | - list 82 | - watch 83 | - update 84 | {{- if .Values.watchdog.enabled }} 85 | - apiGroups: 86 | - metrics.k8s.io 87 | resources: 88 | - pods 89 | verbs: 90 | - list 91 | {{- end }} 92 | --- 93 | apiVersion: rbac.authorization.k8s.io/v1 94 | kind: ClusterRoleBinding 95 | metadata: 96 | name: {{ include "helm.fullname" . }}-manager-rolebinding 97 | labels: 98 | {{- include "helm.labels" . | nindent 4 }} 99 | app.kubernetes.io/component: rbac 100 | app.kubernetes.io/created-by: lumigo 101 | app.kubernetes.io/part-of: lumigo 102 | roleRef: 103 | apiGroup: rbac.authorization.k8s.io 104 | kind: ClusterRole 105 | name: '{{ include "helm.fullname" . }}-manager-role' 106 | subjects: 107 | - kind: ServiceAccount 108 | name: 'lumigo-kubernetes-operator' 109 | namespace: '{{ .Release.Namespace }}' 110 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/README.md: -------------------------------------------------------------------------------- 1 | # Lumigo Operator End-to-End tests on EKS 2 | 3 | ## Setup 4 | 5 | ### Software to have on hand 6 | 7 | 1. Node.js v14+ installed 8 | 1. A local Docker daemon installed that can run `docker build` as the user that you are running the commands in the [Run](#run) section 9 | 1. AWS CLI ([installation instructions](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)) 10 | 1. Local setup of the AWS CLI: 11 | ```sh 12 | aws configure 13 | ``` 14 | 1. AWS Cloud Development Kit (CDK) v2 ([installation instructions](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html)) 15 | 16 | ### Pre-run setup 17 | 18 | 1. AWS Cloud Development Kit (CDK) v2 bootstrapped: 19 | ```sh 20 | cdk bootstrap 21 | ``` 22 | 1. Setup environment variables for sending to Lumigo: `LUMIGO_TRACER_TOKEN` and `LUMIGO_ENDPOINT` 23 | 24 | ## Run 25 | 26 | Install all subdirectories dependencies 27 | ```sh 28 | find . -name node_modules -prune -o -name package.json -execdir npm install \; && rm -rf package-lock.json 29 | ``` 30 | 31 | ``` 32 | npm install 33 | cdk deploy --all 34 | ``` 35 | 36 | 37 | ## Connect to EKS 38 | 39 | IAM with Amazon EKS is _difficult_. 40 | By default, only someone with the **creator role** for EKS can generate a configuration for `kubeconfig` that can access the cluster. 41 | The solution is to create a trust relation between the CreatorRole for the cluster and your user's principal: 42 | 43 | 1. Open the `` provided by the CDK in the AWS Console IAM Roles view. 44 | 1. Click on "Trust relationships" 45 | 1. Click on "Edit trust policy" 46 | 1. Append the JSON snippet generated with the following command to the `Statements` JSON list: 47 | ```sh 48 | aws sts get-caller-identity | jq -r '.Arn | {"Effect":"Allow","Action":"sts:AssumeRole","Principal":{"AWS":.}}' 49 | ``` 50 | 1. Get an updated `kubeconfig` configuration with: 51 | ```sh 52 | aws eks update-kubeconfig --region --name --role-arn 53 | ``` 54 | 55 | To validate, run: 56 | 57 | ```sh 58 | kubeconfig get nodes 59 | ``` 60 | 61 | Happy debugging! 62 | 63 | ## Other useful commands 64 | 65 | * `npm run watch` watch for changes and compile 66 | * `npm run test` perform the jest unit tests 67 | * `cdk diff` compare deployed stack with current state 68 | * `cdk synth` emits the synthesized CloudFormation template 69 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/amazon-eks/cdk/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/cdk.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 38 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 39 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 40 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 41 | "@aws-cdk/aws-route53-patters:useCertificate": true, 42 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 43 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 44 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 45 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 46 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 47 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 48 | "@aws-cdk/aws-redshift:columnId": true, 49 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 50 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 51 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 52 | "@aws-cdk/aws-kms:aliasNameRef": true, 53 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /config/watchdog/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: watchdog 5 | namespace: system 6 | labels: 7 | control-plane: watchdog 8 | app.kubernetes.io/name: deployment 9 | app.kubernetes.io/instance: watchdog 10 | app.kubernetes.io/component: watchdog 11 | app.kubernetes.io/created-by: lumigo 12 | app.kubernetes.io/part-of: lumigo 13 | app.kubernetes.io/managed-by: kustomize 14 | lumigo.auto-trace: "false" 15 | spec: 16 | replicas: 1 17 | selector: 18 | matchLabels: 19 | control-plane: watchdog 20 | template: 21 | metadata: 22 | labels: 23 | control-plane: watchdog 24 | lumigo.auto-trace: "false" 25 | spec: 26 | affinity: 27 | nodeAffinity: 28 | requiredDuringSchedulingIgnoredDuringExecution: 29 | nodeSelectorTerms: 30 | - matchExpressions: 31 | - key: kubernetes.io/arch 32 | operator: In 33 | values: 34 | - amd64 35 | - arm64 36 | - key: kubernetes.io/os 37 | operator: In 38 | values: 39 | - linux 40 | securityContext: 41 | runAsNonRoot: true 42 | fsGroup: 1234 43 | serviceAccountName: controller-manager 44 | containers: 45 | - name: watchdog 46 | image: host.docker.internal:5000/watchdog:latest 47 | command: ["/watchdog"] 48 | env: 49 | - name: LUMIGO_OPERATOR_VERSION 50 | value: latest 51 | - name: LUMIGO_OPERATOR_NAMESPACE 52 | valueFrom: 53 | fieldRef: 54 | fieldPath: metadata.namespace 55 | - name: LUMIGO_METRICS_ENDPOINT 56 | value: https://ga-otlp.lumigo-tracer-edge.golumigo.com 57 | - name: LUMIGO_LOGS_ENDPOINT 58 | value: https://ga-otlp.lumigo-tracer-edge.golumigo.com 59 | - name: LUMIGO_DEBUG 60 | value: "false" 61 | resources: 62 | limits: 63 | cpu: 500m 64 | memory: 128Mi 65 | requests: 66 | cpu: 10m 67 | memory: 64Mi 68 | securityContext: 69 | allowPrivilegeEscalation: false 70 | capabilities: 71 | drop: 72 | - ALL 73 | readOnlyRootFilesystem: true 74 | runAsNonRoot: true 75 | runAsUser: 1234 -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/leader-election-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | name: {{ include "helm.fullname" . }}-leader-election-role 5 | labels: 6 | {{- include "helm.labels" . | nindent 4 }} 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: lumigo 9 | app.kubernetes.io/part-of: lumigo 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - configmaps 15 | verbs: 16 | - get 17 | - list 18 | - watch 19 | - create 20 | - update 21 | - patch 22 | - delete 23 | - apiGroups: 24 | - coordination.k8s.io 25 | resources: 26 | - leases 27 | verbs: 28 | - get 29 | - list 30 | - watch 31 | - create 32 | - update 33 | - patch 34 | - delete 35 | - apiGroups: 36 | - "" 37 | resources: 38 | - events 39 | verbs: 40 | - create 41 | - patch 42 | --- 43 | apiVersion: rbac.authorization.k8s.io/v1 44 | kind: RoleBinding 45 | metadata: 46 | name: {{ include "helm.fullname" . }}-leader-election-rolebinding 47 | labels: 48 | {{- include "helm.labels" . | nindent 4 }} 49 | app.kubernetes.io/component: rbac 50 | app.kubernetes.io/created-by: lumigo 51 | app.kubernetes.io/part-of: lumigo 52 | roleRef: 53 | apiGroup: rbac.authorization.k8s.io 54 | kind: Role 55 | name: '{{ include "helm.fullname" . }}-leader-election-role' 56 | subjects: 57 | - kind: ServiceAccount 58 | name: 'lumigo-kubernetes-operator' 59 | namespace: '{{ .Release.Namespace }}' 60 | --- 61 | apiVersion: rbac.authorization.k8s.io/v1 62 | kind: ClusterRole 63 | metadata: 64 | name: {{ include "helm.fullname" . }}-quickstart-management 65 | labels: 66 | {{- include "helm.labels" . | nindent 4 }} 67 | app.kubernetes.io/component: rbac 68 | app.kubernetes.io/created-by: lumigo 69 | app.kubernetes.io/part-of: lumigo 70 | rules: 71 | - apiGroups: 72 | - "" 73 | resources: 74 | - secrets 75 | - lumigoes 76 | verbs: 77 | - create 78 | --- 79 | apiVersion: rbac.authorization.k8s.io/v1 80 | kind: ClusterRoleBinding 81 | metadata: 82 | name: {{ include "helm.fullname" . }}-quickstart-management 83 | labels: 84 | {{- include "helm.labels" . | nindent 4 }} 85 | app.kubernetes.io/component: rbac 86 | app.kubernetes.io/created-by: lumigo 87 | app.kubernetes.io/part-of: lumigo 88 | roleRef: 89 | apiGroup: rbac.authorization.k8s.io 90 | kind: ClusterRole 91 | name: '{{ include "helm.fullname" . }}-quickstart-management' 92 | subjects: 93 | - kind: ServiceAccount 94 | name: 'lumigo-kubernetes-operator' 95 | namespace: '{{ .Release.Namespace }}' -------------------------------------------------------------------------------- /telemetryproxy/src/Makefile: -------------------------------------------------------------------------------- 1 | MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) 2 | SRC_ROOT := $(dir $(MAKEFILE_PATH)) 3 | VERSION := dev 4 | 5 | # build tags required by any component should be defined as an independent variables and later added to GO_BUILD_TAGS below 6 | GO_BUILD_TAGS="" 7 | GOTEST_OPT?= -race -timeout 300s -parallel 4 --tags=$(GO_BUILD_TAGS) 8 | GOTEST_INTEGRATION_OPT?= -race -timeout 360s -parallel 4 9 | GOTEST_OPT_WITH_COVERAGE = $(GOTEST_OPT) -coverprofile=coverage.txt -covermode=atomic 10 | GOTEST_OPT_WITH_INTEGRATION=$(GOTEST_INTEGRATION_OPT) -tags=integration,$(GO_BUILD_TAGS) -run=Integration -coverprofile=integration-coverage.txt -covermode=atomic 11 | GOCMD?= go 12 | GOTEST=$(GOCMD) test 13 | GOOS=$(shell $(GOCMD) env GOOS) 14 | GOARCH=$(shell $(GOCMD) env GOARCH) 15 | 16 | TOOLS_MOD_DIR := $(SRC_ROOT)internal/tools 17 | TOOLS_MOD_REGEX := "\s+_\s+\".*\"" 18 | TOOLS_PKG_NAMES := $(shell grep -E $(TOOLS_MOD_REGEX) < $(TOOLS_MOD_DIR)/tools.go | tr -d " _\"") 19 | TOOLS_BIN_DIR := $(SRC_ROOT).tools 20 | TOOLS_BIN_NAMES := $(addprefix $(TOOLS_BIN_DIR)/, $(notdir $(TOOLS_PKG_NAMES))) 21 | 22 | .PHONY: install-tools 23 | install-tools: $(TOOLS_BIN_NAMES) 24 | 25 | $(TOOLS_BIN_DIR): 26 | mkdir -p $@ 27 | 28 | $(TOOLS_BIN_NAMES): $(TOOLS_BIN_DIR) $(TOOLS_MOD_DIR)/go.mod 29 | cd $(TOOLS_MOD_DIR) && GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOCMD) build -o $@ -trimpath $(filter %/$(notdir $@),$(TOOLS_PKG_NAMES)) 30 | 31 | ADDLICENCESE := $(TOOLS_BIN_DIR)/addlicense 32 | MDLINKCHECK := $(TOOLS_BIN_DIR)/markdown-link-check 33 | MISSPELL := $(TOOLS_BIN_DIR)/misspell -error 34 | MISSPELL_CORRECTION := $(TOOLS_BIN_DIR)/misspell -w 35 | LINT := $(TOOLS_BIN_DIR)/golangci-lint 36 | MULITMOD := $(TOOLS_BIN_DIR)/multimod 37 | CHLOGGEN := $(TOOLS_BIN_DIR)/chloggen 38 | GOIMPORTS := $(TOOLS_BIN_DIR)/goimports 39 | PORTO := $(TOOLS_BIN_DIR)/porto 40 | CHECKDOC := $(TOOLS_BIN_DIR)/checkdoc 41 | CROSSLINK := $(TOOLS_BIN_DIR)/crosslink 42 | GOJUNIT := $(TOOLS_BIN_DIR)/go-junit-report 43 | BUILDER := $(TOOLS_BIN_DIR)/builder 44 | 45 | OTELCONTRIBCOL_FILENAME := "./otelcontribcol_$(GOOS)_$(GOARCH)$(EXTENSION)" 46 | 47 | .PHONY: otelcontribcolbuilder 48 | otelcontribcolbuilder: install-tools $(BUILDER) 49 | # Split source generation and compilation in two steps, because the GOARCH and GOOS may be different when cross-compiling 50 | mkdir -p ./dist 51 | $(BUILDER) --skip-compilation --config ./builder/config.yaml 52 | cd ./dist/ && GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=0 $(GOCMD) build -trimpath -o $(OTELCONTRIBCOL_FILENAME) \ 53 | $(BUILD_INFO) -tags $(GO_BUILD_TAGS) . 54 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/lumigooperatorheartbeatreceiver/factory.go: -------------------------------------------------------------------------------- 1 | package lumigooperatorheartbeatreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/lumigooperatorheartbeatreceiver" 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync" 7 | 8 | "go.opentelemetry.io/collector/component" 9 | "go.opentelemetry.io/collector/consumer" 10 | "go.opentelemetry.io/collector/receiver" 11 | "go.opentelemetry.io/collector/receiver/receiverhelper" 12 | "go.uber.org/zap" 13 | "k8s.io/client-go/dynamic" 14 | 15 | "github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig" 16 | ) 17 | 18 | var ( 19 | componentType = component.MustNewType("lumigooperatorheartbeat") 20 | ) 21 | 22 | var ( 23 | singletonKube dynamic.Interface 24 | singletonKubeMutex sync.Mutex 25 | ) 26 | 27 | func createDefaultConfig() component.Config { 28 | return &Config{} 29 | } 30 | 31 | func createLumigooperatorheartbeatReceiver(_ context.Context, params receiver.Settings, baseCfg component.Config, consumer consumer.Logs) (receiver.Logs, error) { 32 | if consumer == nil { 33 | return nil, fmt.Errorf("nextConsumer cannot be nil") 34 | } 35 | 36 | cfg := baseCfg.(*Config) 37 | 38 | kubeClient, err := initKubeClient() 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | obsrecv, err := receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{ 44 | ReceiverID: params.ID, 45 | Transport: "http", 46 | ReceiverCreateSettings: params, 47 | }) 48 | if err != nil { 49 | return nil, fmt.Errorf("cannot create a new receiver: %w", err) 50 | } 51 | 52 | logsRcvr := &lumigooperatorheartbeatReceiver{ 53 | kube: kubeClient, 54 | config: cfg, 55 | consumer: consumer, 56 | obsrecv: obsrecv, 57 | logger: params.Logger.With(zap.String("namespace", cfg.Namespace)), 58 | } 59 | 60 | return logsRcvr, nil 61 | } 62 | 63 | func initKubeClient() (dynamic.Interface, error) { 64 | // Synchronize singleton instantiation, as there might be multiple 65 | // instances of the processor being bootstrapped on different pipelines 66 | if singletonKube != nil { 67 | return singletonKube, nil 68 | } 69 | 70 | singletonKubeMutex.Lock() 71 | defer singletonKubeMutex.Unlock() 72 | 73 | client, err := k8sconfig.MakeDynamicClient(k8sconfig.APIConfig{AuthType: k8sconfig.AuthTypeServiceAccount}) 74 | if err != nil { 75 | return nil, err 76 | } 77 | 78 | singletonKube = client 79 | 80 | return client, nil 81 | } 82 | 83 | func NewFactory() receiver.Factory { 84 | return receiver.NewFactory( 85 | componentType, 86 | createDefaultConfig, 87 | receiver.WithLogs(createLumigooperatorheartbeatReceiver, component.StabilityLevelAlpha)) 88 | } 89 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/installation/install-upgrade-hook.yaml: -------------------------------------------------------------------------------- 1 | {{ if and .Values.lumigoToken .Values.monitoredNamespaces }} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "helm.fullname" . }}-install-hook 6 | labels: 7 | {{- include "helm.labels" . | nindent 4 }} 8 | app.kubernetes.io/component: manager 9 | app.kubernetes.io/created-by: lumigo 10 | app.kubernetes.io/part-of: lumigo 11 | control-plane: controller-manager 12 | lumigo.auto-trace: 'false' # We do not need the operator to inject itself 13 | annotations: 14 | helm.sh/hook: post-install,post-upgrade 15 | {{- if not .Values.debug.enabled }} 16 | helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded # we skip hook-failed, so the job will be kept for troubleshooting in case of a failure 17 | {{- end }} 18 | 19 | spec: 20 | completions: 1 21 | backoffLimit: 2 22 | template: 23 | metadata: 24 | name: "{{ .Release.Name }}" 25 | labels: 26 | {{- include "helm.selectorLabels" . | nindent 8 }} 27 | lumigo.auto-trace: 'false' # We do not need the operator to inject itself 28 | control-plane: controller-manager 29 | spec: 30 | restartPolicy: Never 31 | activeDeadlineSeconds: 120 # Unfortunately, as of v3.11, Helm does not expose to templates its own timeout 32 | containers: 33 | - name: install-hook 34 | image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }} 35 | command: 36 | - "/manager" 37 | args: 38 | - --quickstart={{ if (toString .Values.monitoredNamespaces) | eq "all" }}all{{ else }}{{ .Values.monitoredNamespaces | toJson }}{{ end }} 39 | - --lumigo-token={{ .Values.lumigoToken.value }} 40 | - --lumigo-namespace={{ .Release.Namespace }} 41 | securityContext: 42 | allowPrivilegeEscalation: false 43 | capabilities: 44 | drop: 45 | - ALL 46 | readOnlyRootFilesystem: true 47 | runAsNonRoot: true 48 | securityContext: 49 | runAsNonRoot: true 50 | fsGroup: 1234 51 | serviceAccountName: lumigo-kubernetes-operator 52 | {{- if or .Values.tolerations.installHook .Values.tolerations.global }} 53 | tolerations: 54 | {{- toYaml (.Values.tolerations.installHook | default .Values.tolerations.global) | nindent 6 }} 55 | {{- end }} 56 | {{- if or .Values.nodeSelector.installHook .Values.nodeSelector.global }} 57 | nodeSelector: 58 | {{- toYaml (.Values.nodeSelector.installHook | default .Values.nodeSelector.global) | nindent 8 }} 59 | {{- end }} 60 | {{- end }} -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/k8sobjectsreceiver/unstructured_to_logdata.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package k8sobjectsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sobjectsreceiver" 5 | 6 | import ( 7 | "fmt" 8 | "time" 9 | 10 | "go.opentelemetry.io/collector/pdata/pcommon" 11 | "go.opentelemetry.io/collector/pdata/plog" 12 | semconv "go.opentelemetry.io/collector/semconv/v1.9.0" 13 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 14 | "k8s.io/apimachinery/pkg/watch" 15 | ) 16 | 17 | type attrUpdaterFunc func(pcommon.Map) 18 | 19 | func watchObjectsToLogData(event *watch.Event, observedAt time.Time, config *K8sObjectsConfig) (plog.Logs, error) { 20 | udata, ok := event.Object.(*unstructured.Unstructured) 21 | if !ok { 22 | return plog.Logs{}, fmt.Errorf("received data that wasnt unstructure, %v", event) 23 | } 24 | 25 | ul := unstructured.UnstructuredList{ 26 | Items: []unstructured.Unstructured{{ 27 | Object: map[string]any{ 28 | "type": string(event.Type), 29 | "object": udata.Object, 30 | }, 31 | }}, 32 | } 33 | 34 | return unstructuredListToLogData(&ul, observedAt, config, func(attrs pcommon.Map) { 35 | objectMeta := udata.Object["metadata"].(map[string]any) 36 | name := objectMeta["name"].(string) 37 | if name != "" { 38 | attrs.PutStr("event.domain", "k8s") 39 | attrs.PutStr("event.name", name) 40 | } 41 | }), nil 42 | } 43 | 44 | func pullObjectsToLogData(event *unstructured.UnstructuredList, observedAt time.Time, config *K8sObjectsConfig) plog.Logs { 45 | return unstructuredListToLogData(event, observedAt, config) 46 | } 47 | 48 | func unstructuredListToLogData(event *unstructured.UnstructuredList, observedAt time.Time, config *K8sObjectsConfig, attrUpdaters ...attrUpdaterFunc) plog.Logs { 49 | out := plog.NewLogs() 50 | resourceLogs := out.ResourceLogs() 51 | namespaceResourceMap := make(map[string]plog.LogRecordSlice) 52 | 53 | for _, e := range event.Items { 54 | logSlice, ok := namespaceResourceMap[e.GetNamespace()] 55 | if !ok { 56 | rl := resourceLogs.AppendEmpty() 57 | resourceAttrs := rl.Resource().Attributes() 58 | if namespace := e.GetNamespace(); namespace != "" { 59 | resourceAttrs.PutStr(semconv.AttributeK8SNamespaceName, namespace) 60 | } 61 | sl := rl.ScopeLogs().AppendEmpty() 62 | logSlice = sl.LogRecords() 63 | namespaceResourceMap[e.GetNamespace()] = logSlice 64 | } 65 | record := logSlice.AppendEmpty() 66 | record.SetObservedTimestamp(pcommon.NewTimestampFromTime(observedAt)) 67 | 68 | attrs := record.Attributes() 69 | attrs.PutStr("k8s.resource.name", config.gvr.Resource) 70 | 71 | for _, attrUpdate := range attrUpdaters { 72 | attrUpdate(attrs) 73 | } 74 | 75 | dest := record.Body() 76 | destMap := dest.SetEmptyMap() 77 | //nolint:errcheck 78 | destMap.FromRaw(e.Object) 79 | } 80 | return out 81 | } 82 | -------------------------------------------------------------------------------- /telemetryproxy/src/builder/config.yaml: -------------------------------------------------------------------------------- 1 | dist: 2 | module: github.com/lumigo-io/lumigo-otel-collector-contrib 3 | # The `name` field becomes the `service.name` resource-attribute of internal metrics exported by the collector, 4 | # recognized by the Lumigo backend. Do not change this without changing it in the backend accordingly. 5 | name: lumigo-collector 6 | description: Lumigo OpenTelemetry collector 7 | version: "0.116.0-dev" 8 | output_path: dist 9 | 10 | exporters: 11 | - gomod: "go.opentelemetry.io/collector/exporter/debugexporter v0.116.0" 12 | - gomod: "go.opentelemetry.io/collector/exporter/otlphttpexporter v0.116.0" 13 | 14 | extensions: 15 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension v0.116.0" 16 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.116.0" 17 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/extension/lumigoauthextension v0.116.0" 18 | 19 | receivers: 20 | - gomod: "go.opentelemetry.io/collector/receiver/otlpreceiver v0.116.0" 21 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/lumigooperatorheartbeatreceiver v0.116.0" 22 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sobjectsreceiver v0.116.0" 23 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/syslogreceiver v0.116.0" 24 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.116.0" 25 | 26 | processors: 27 | - gomod: "go.opentelemetry.io/collector/processor/batchprocessor v0.116.0" 28 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor v0.116.0" 29 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor v0.116.0" 30 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sdataenricherprocessor v0.116.0" 31 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor v0.116.0" 32 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor v0.116.0" 33 | 34 | connectors: 35 | - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/connector/routingconnector v0.116.0" 36 | 37 | replaces: 38 | - github.com/open-telemetry/opentelemetry-collector-contrib/extension/lumigoauthextension v0.116.0 => github.com/lumigo-io/lumigo-otel-collector-contrib/extension/lumigoauthextension main 39 | - github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sdataenricherprocessor v0.116.0 => ../processor/k8sdataenricherprocessor 40 | - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/lumigooperatorheartbeatreceiver v0.116.0 => ../receiver/lumigooperatorheartbeatreceiver 41 | - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sobjectsreceiver v0.116.0 => ../receiver/k8sobjectsreceiver 42 | -------------------------------------------------------------------------------- /tests/quickstart/internal/build_docker_image.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | 10 | "github.com/docker/docker/api/types" 11 | "github.com/docker/docker/client" 12 | "github.com/docker/docker/pkg/archive" 13 | "sigs.k8s.io/e2e-framework/pkg/env" 14 | "sigs.k8s.io/e2e-framework/pkg/envconf" 15 | ) 16 | 17 | const ( 18 | DEFAULT_JS_CLIENT_IMG_NAME = "host.docker.internal:5000/test-apps/js/client" 19 | DEFAULT_JS_SERVER_IMG_NAME = "host.docker.internal:5000/test-apps/js/server" 20 | DEFAULT_PYTHON_IMG_NAME = "host.docker.internal:5000/test-apps/python-app" 21 | ) 22 | 23 | func BuildDockerImageAndExportArchive(imageName, sourceFolder, imageArchivePath string, logger *log.Logger) env.Func { 24 | return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { 25 | logger.Printf("Building '%s' image", imageName) 26 | 27 | cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) 28 | if err != nil { 29 | return ctx, fmt.Errorf("cannot create Docker client: %w", err) 30 | } 31 | defer cli.Close() 32 | 33 | tar, err := archive.TarWithOptions(sourceFolder, &archive.TarOptions{}) 34 | if err != nil { 35 | return ctx, fmt.Errorf("cannot create tar archive for Docker build context: %w", err) 36 | } 37 | 38 | { 39 | res, err := cli.ImageBuild(ctx, tar, types.ImageBuildOptions{ 40 | Dockerfile: "Dockerfile", 41 | Tags: []string{imageName}, 42 | Remove: true, 43 | }) 44 | if _, err1 := io.Copy(logger.Writer(), res.Body); err1 != nil { 45 | logger.Fatalf("cannot read ImageBuild output: %v", err1) 46 | } 47 | if err != nil { 48 | return ctx, fmt.Errorf("cannot build '%s' image: %w", imageName, err) 49 | } 50 | defer res.Body.Close() 51 | logger.Printf("Image '%s' built", imageName) 52 | } 53 | 54 | if imageArchivePath != "" { 55 | logger.Printf("Saving '%s' image to path '%s'", imageName, imageArchivePath) 56 | if err := saveDockerImageToPath(ctx, cli, imageName, imageArchivePath); err != nil { 57 | return ctx, fmt.Errorf("cannot save '%s' image to path '%s': %w", imageName, imageArchivePath, err) 58 | } 59 | 60 | logger.Printf("Image '%s' saved to path '%s'", imageName, imageArchivePath) 61 | } 62 | 63 | return ctx, nil 64 | } 65 | } 66 | 67 | func saveDockerImageToPath(ctx context.Context, cli *client.Client, imageName, imageArchivePath string) error { 68 | f, err := os.Create(imageArchivePath) 69 | if err != nil { 70 | return fmt.Errorf("cannot open file '%s': %w", imageArchivePath, err) 71 | } 72 | defer f.Close() 73 | 74 | r, err := cli.ImageSave(ctx, []string{imageName}) 75 | if err != nil { 76 | return fmt.Errorf("cannot get reader for '%s' image: %w", imageName, err) 77 | } 78 | defer r.Close() 79 | 80 | if _, err := io.Copy(f, r); err != nil { 81 | return fmt.Errorf("an error occurred while copying archive for '%s' image to '%s': %w", imageName, imageArchivePath, err) 82 | } 83 | 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/internal/build_docker_image.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | 10 | "github.com/docker/docker/api/types" 11 | "github.com/docker/docker/client" 12 | "github.com/docker/docker/pkg/archive" 13 | "sigs.k8s.io/e2e-framework/pkg/env" 14 | "sigs.k8s.io/e2e-framework/pkg/envconf" 15 | ) 16 | 17 | const ( 18 | DEFAULT_JS_CLIENT_IMG_NAME = "host.docker.internal:5000/test-apps/js/client" 19 | DEFAULT_JS_SERVER_IMG_NAME = "host.docker.internal:5000/test-apps/js/server" 20 | DEFAULT_PYTHON_IMG_NAME = "host.docker.internal:5000/test-apps/python-app" 21 | ) 22 | 23 | func BuildDockerImageAndExportArchive(imageName, sourceFolder, imageArchivePath string, logger *log.Logger) env.Func { 24 | return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { 25 | logger.Printf("Building '%s' image", imageName) 26 | 27 | cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) 28 | if err != nil { 29 | return ctx, fmt.Errorf("cannot create Docker client: %w", err) 30 | } 31 | defer cli.Close() 32 | 33 | tar, err := archive.TarWithOptions(sourceFolder, &archive.TarOptions{}) 34 | if err != nil { 35 | return ctx, fmt.Errorf("cannot create tar archive for Docker build context: %w", err) 36 | } 37 | 38 | { 39 | res, err := cli.ImageBuild(ctx, tar, types.ImageBuildOptions{ 40 | Dockerfile: "Dockerfile", 41 | Tags: []string{imageName}, 42 | Remove: true, 43 | }) 44 | if _, err1 := io.Copy(logger.Writer(), res.Body); err1 != nil { 45 | logger.Fatalf("cannot read ImageBuild output: %v", err1) 46 | } 47 | if err != nil { 48 | return ctx, fmt.Errorf("cannot build '%s' image: %w", imageName, err) 49 | } 50 | defer res.Body.Close() 51 | logger.Printf("Image '%s' built", imageName) 52 | } 53 | 54 | if imageArchivePath != "" { 55 | logger.Printf("Saving '%s' image to path '%s'", imageName, imageArchivePath) 56 | if err := saveDockerImageToPath(ctx, cli, imageName, imageArchivePath); err != nil { 57 | return ctx, fmt.Errorf("cannot save '%s' image to path '%s': %w", imageName, imageArchivePath, err) 58 | } 59 | 60 | logger.Printf("Image '%s' saved to path '%s'", imageName, imageArchivePath) 61 | } 62 | 63 | return ctx, nil 64 | } 65 | } 66 | 67 | func saveDockerImageToPath(ctx context.Context, cli *client.Client, imageName, imageArchivePath string) error { 68 | f, err := os.Create(imageArchivePath) 69 | if err != nil { 70 | return fmt.Errorf("cannot open file '%s': %w", imageArchivePath, err) 71 | } 72 | defer f.Close() 73 | 74 | r, err := cli.ImageSave(ctx, []string{imageName}) 75 | if err != nil { 76 | return fmt.Errorf("cannot get reader for '%s' image: %w", imageName, err) 77 | } 78 | defer r.Close() 79 | 80 | if _, err := io.Copy(f, r); err != nil { 81 | return fmt.Errorf("an error occurred while copying archive for '%s' image to '%s': %w", imageName, imageArchivePath, err) 82 | } 83 | 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/watchdog-deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.watchdog.enabled }} 2 | {{- $lumigoOperatorVersion := .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }} 3 | --- 4 | apiVersion: apps/v1 5 | kind: Deployment 6 | metadata: 7 | name: {{ include "helm.fullname" . }}-watchdog 8 | labels: 9 | {{- include "helm.labels" . | nindent 4 }} 10 | app.kubernetes.io/component: watchdog 11 | app.kubernetes.io/created-by: lumigo 12 | app.kubernetes.io/part-of: lumigo 13 | control-plane: watchdog 14 | lumigo.auto-trace: 'false' # We do not need the operator to inject itself 15 | spec: 16 | replicas: 1 17 | selector: 18 | matchLabels: 19 | control-plane: watchdog 20 | {{- include "helm.selectorLabels" . | nindent 6 }} 21 | template: 22 | metadata: 23 | labels: 24 | control-plane: watchdog 25 | {{- include "helm.selectorLabels" . | nindent 8 }} 26 | spec: 27 | affinity: 28 | nodeAffinity: 29 | requiredDuringSchedulingIgnoredDuringExecution: 30 | nodeSelectorTerms: 31 | - matchExpressions: 32 | - key: kubernetes.io/arch 33 | operator: In 34 | values: 35 | - amd64 36 | - arm64 37 | - key: kubernetes.io/os 38 | operator: In 39 | values: 40 | - linux 41 | serviceAccountName: lumigo-kubernetes-operator 42 | {{- if or .Values.tolerations.watchdog .Values.tolerations.global }} 43 | tolerations: 44 | {{- toYaml (.Values.tolerations.watchdog | default .Values.tolerations.global) | nindent 6 }} 45 | {{- end }} 46 | {{- if or .Values.nodeSelector.watchdog .Values.nodeSelector.global }} 47 | nodeSelector: 48 | {{- toYaml (.Values.nodeSelector.watchdog | default .Values.nodeSelector.global) | nindent 8 }} 49 | {{- end }} 50 | containers: 51 | - name: watchdog 52 | image: {{ .Values.watchdog.image.repository }}:{{ .Values.watchdog.image.tag }} 53 | command: ["/watchdog"] 54 | env: 55 | - name: LUMIGO_OPERATOR_VERSION 56 | value: "{{ $lumigoOperatorVersion }}" 57 | - name: LUMIGO_OPERATOR_NAMESPACE 58 | value: "{{ .Release.Namespace }}" 59 | - name: LUMIGO_METRICS_ENDPOINT 60 | value: "{{ .Values.endpoint.otlp.metrics_url }}" 61 | - name: LUMIGO_LOGS_ENDPOINT 62 | value: "{{ .Values.endpoint.otlp.logs_url }}" 63 | - name: LUMIGO_DEBUG 64 | value: "{{ .Values.debug.enabled | default false }}" 65 | - name: LUMIGO_WATCHDOG_TOP_WATCHER_INTERVAL 66 | value: "{{ .Values.watchdog.watchers.top.frequency }}" 67 | {{- if .Values.cluster.name }} 68 | - name: KUBERNETES_CLUSTER_NAME 69 | value: "{{ .Values.cluster.name }}" 70 | {{- end }} 71 | {{- if .Values.lumigoToken }} 72 | - name: LUMIGO_INFRA_METRICS_TOKEN 73 | valueFrom: 74 | secretKeyRef: 75 | name: {{ .Values.lumigoToken.secretName }} 76 | key: {{ .Values.lumigoToken.secretKey }} 77 | optional: true 78 | {{- end }} 79 | resources: {{- toYaml .Values.watchdog.resources | nindent 8 }} 80 | {{- end }} 81 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/lumigooperatorheartbeatreceiver/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/lumigooperatorheartbeatreceiver 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.8 6 | 7 | require ( 8 | github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig v0.116.0 9 | go.opentelemetry.io/collector/component v0.116.0 10 | go.opentelemetry.io/collector/consumer v1.22.0 11 | go.opentelemetry.io/collector/pdata v1.22.0 12 | go.opentelemetry.io/collector/receiver v0.116.0 13 | go.uber.org/zap v1.27.0 14 | k8s.io/apimachinery v0.31.3 15 | k8s.io/client-go v0.31.3 16 | ) 17 | 18 | require ( 19 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 20 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect 21 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 22 | github.com/go-logr/logr v1.4.2 // indirect 23 | github.com/go-openapi/jsonpointer v0.19.6 // indirect 24 | github.com/go-openapi/jsonreference v0.20.2 // indirect 25 | github.com/go-openapi/swag v0.22.4 // indirect 26 | github.com/gogo/protobuf v1.3.2 // indirect 27 | github.com/golang/protobuf v1.5.4 // indirect 28 | github.com/google/gnostic-models v0.6.8 // indirect 29 | github.com/google/go-cmp v0.6.0 // indirect 30 | github.com/google/gofuzz v1.2.0 // indirect 31 | github.com/google/uuid v1.6.0 // indirect 32 | github.com/imdario/mergo v0.3.13 // indirect 33 | github.com/josharian/intern v1.0.0 // indirect 34 | github.com/json-iterator/go v1.1.12 // indirect 35 | github.com/mailru/easyjson v0.7.7 // indirect 36 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 37 | github.com/modern-go/reflect2 v1.0.2 // indirect 38 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 39 | github.com/openshift/api v3.9.0+incompatible // indirect 40 | github.com/openshift/client-go v0.0.0-20210521082421-73d9475a9142 // indirect 41 | github.com/spf13/pflag v1.0.5 // indirect 42 | github.com/x448/float16 v0.8.4 // indirect 43 | go.opentelemetry.io/collector/config/configtelemetry v0.116.0 // indirect 44 | go.opentelemetry.io/collector/pipeline v0.116.0 // indirect 45 | go.opentelemetry.io/otel v1.32.0 // indirect 46 | go.opentelemetry.io/otel/metric v1.32.0 // indirect 47 | go.opentelemetry.io/otel/trace v1.32.0 // indirect 48 | go.uber.org/multierr v1.11.0 // indirect 49 | golang.org/x/net v0.38.0 // indirect 50 | golang.org/x/oauth2 v0.27.0 // indirect 51 | golang.org/x/sys v0.31.0 // indirect 52 | golang.org/x/term v0.30.0 // indirect 53 | golang.org/x/text v0.23.0 // indirect 54 | golang.org/x/time v0.4.0 // indirect 55 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect 56 | google.golang.org/grpc v1.68.1 // indirect 57 | google.golang.org/protobuf v1.35.2 // indirect 58 | gopkg.in/inf.v0 v0.9.1 // indirect 59 | gopkg.in/yaml.v2 v2.4.0 // indirect 60 | gopkg.in/yaml.v3 v3.0.1 // indirect 61 | k8s.io/api v0.31.3 // indirect 62 | k8s.io/klog/v2 v2.130.1 // indirect 63 | k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect 64 | k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect 65 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 66 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect 67 | sigs.k8s.io/yaml v1.4.0 // indirect 68 | ) 69 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "helm.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "helm.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "helm.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "helm.labels" -}} 37 | helm.sh/chart: {{ include "helm.chart" . }} 38 | {{ include "helm.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "helm.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "helm.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "helm.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "helm.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | 64 | {{/* 65 | Returns the error in the status condition if the Lumigo resource passed in input, 66 | if any; otherwise, returns nil. 67 | */}} 68 | {{- define "lumigo.error" }} 69 | {{- $lumigo := . }} 70 | {{- if $lumigo.status }} 71 | {{- range $index, $condition := $lumigo.status.conditions }} 72 | {{- if and (eq $condition.type "Error") (ne $condition.status "False") }} 73 | {{- $condition.message }} 74 | {{- end }} 75 | {{- end }} 76 | {{- end }} 77 | {{- end }} 78 | 79 | {{/* 80 | If the output is a shell, introduce ANSI colors around the provided text 81 | */}} 82 | {{- define "highlight" -}} 83 | {{- $message := index . 0 -}} 84 | {{- $color := index . 1 -}} 85 | {{- $coloredOutput := index . 2 -}} 86 | {{- $colorPoint := 33 }} 87 | {{- if eq $color "red" -}} 88 | {{- $colorPoint = 31 }} 89 | {{- else if eq $color "green" }} 90 | {{- $colorPoint = 32 }} 91 | {{- else if eq $color "orange" }} 92 | {{- $colorPoint = 33 }} 93 | {{- else if eq $color "magenta" }} 94 | {{- $colorPoint = 35 }} 95 | {{- else if eq $color "cyan" }} 96 | {{- $colorPoint = 36 }} 97 | {{- end }} 98 | {{- if and ($coloredOutput) (eq $coloredOutput true) -}} 99 | {{ printf "[%sm%s" ($colorPoint | toString) $message -}} 100 | {{- else -}} 101 | {{ printf "%s" $message -}} 102 | {{- end }} 103 | {{- end }} -------------------------------------------------------------------------------- /controller/src/controllers/telemetryproxyconfigs/namespace_monitoring_configs.go: -------------------------------------------------------------------------------- 1 | package telemetryproxyconfigs 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "os" 9 | "sort" 10 | 11 | "github.com/go-logr/logr" 12 | ) 13 | 14 | type NamespaceMonitoringConfig struct { 15 | Token string `json:"token"` 16 | Name string `json:"name"` 17 | Uid string `json:"uid"` 18 | } 19 | 20 | func RemoveTelemetryProxyMonitoringOfNamespace(ctx context.Context, telemetryProxyNamespaceConfigurationsPath string, namespaceName string, log *logr.Logger) (bool, error) { 21 | return updateTelemetryProxyMonitoringOfNamespace(ctx, telemetryProxyNamespaceConfigurationsPath, &NamespaceMonitoringConfig{ 22 | Name: namespaceName, 23 | }, log) 24 | } 25 | 26 | func UpsertTelemetryProxyMonitoringOfNamespace(ctx context.Context, telemetryProxyNamespaceConfigurationsPath string, namespaceName string, namespaceUid string, token string, log *logr.Logger) (bool, error) { 27 | return updateTelemetryProxyMonitoringOfNamespace(ctx, telemetryProxyNamespaceConfigurationsPath, &NamespaceMonitoringConfig{ 28 | Name: namespaceName, 29 | Uid: namespaceUid, 30 | Token: token, 31 | }, log) 32 | } 33 | 34 | func updateTelemetryProxyMonitoringOfNamespace(ctx context.Context, telemetryProxyNamespaceConfigurationsPath string, namespaceMonitoringConfig *NamespaceMonitoringConfig, log *logr.Logger) (bool, error) { 35 | upsert := len(namespaceMonitoringConfig.Uid) > 0 36 | 37 | var namespaces []NamespaceMonitoringConfig 38 | namespacesFileBytes, err := os.ReadFile(telemetryProxyNamespaceConfigurationsPath) 39 | if err != nil { 40 | if !os.IsNotExist(err) { 41 | return false, fmt.Errorf("cannot read namespace configuration file '%s': %w", telemetryProxyNamespaceConfigurationsPath, err) 42 | } 43 | } else if err := json.Unmarshal(namespacesFileBytes, &namespaces); err != nil { 44 | return false, fmt.Errorf("cannot unmarshal namespace configuration file '%s': %w", telemetryProxyNamespaceConfigurationsPath, err) 45 | } 46 | 47 | var newNamespaces []NamespaceMonitoringConfig 48 | // Keep all other namespaces to the new file 49 | for _, namespace := range namespaces { 50 | if namespace.Name != namespaceMonitoringConfig.Name && len(namespaceMonitoringConfig.Name) > 0 { 51 | newNamespaces = append(newNamespaces, namespace) 52 | } 53 | } 54 | 55 | if upsert { 56 | newNamespaces = append(newNamespaces, *namespaceMonitoringConfig) 57 | } 58 | 59 | // Sort namespace structs by namespace name 60 | sort.Slice(newNamespaces, func(i, j int) bool { 61 | return newNamespaces[i].Name < newNamespaces[j].Name 62 | }) 63 | 64 | // The marhsalling is with sorted keys, so the resulting bytes are deterministic 65 | updatedNamespacesFileBytes, err := json.Marshal(newNamespaces) 66 | if err != nil { 67 | return false, fmt.Errorf("cannot marshal the updated namespace configuration: %w", err) 68 | } 69 | 70 | if bytes.Equal(namespacesFileBytes, updatedNamespacesFileBytes) { 71 | // Nothing to change 72 | return false, nil 73 | } 74 | 75 | if err := os.WriteFile(telemetryProxyNamespaceConfigurationsPath, updatedNamespacesFileBytes, 0644); err != nil { 76 | return false, fmt.Errorf("cannot write the updated namespace configuration file '%s': %w", telemetryProxyNamespaceConfigurationsPath, err) 77 | } 78 | 79 | log.Info("Updated namespace monitoring configurations", "new_configurations", newNamespaces) 80 | 81 | return true, nil 82 | } 83 | -------------------------------------------------------------------------------- /telemetryproxy/src/processor/k8sdataenricherprocessor/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sdataenricherprocessor 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.8 6 | 7 | require ( 8 | github.com/hashicorp/golang-lru/v2 v2.0.4 9 | github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig v0.116.0 10 | go.opentelemetry.io/collector/client v0.116.0 11 | go.opentelemetry.io/collector/component v0.116.0 12 | go.opentelemetry.io/collector/consumer v0.116.0 13 | go.opentelemetry.io/collector/pdata v0.116.0 14 | go.opentelemetry.io/collector/processor v0.116.0 15 | go.opentelemetry.io/otel v1.36.0 16 | go.uber.org/zap v1.27.0 17 | k8s.io/api v0.31.3 18 | k8s.io/apimachinery v0.31.3 19 | k8s.io/client-go v0.31.3 20 | ) 21 | 22 | require ( 23 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 24 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect 25 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 26 | github.com/go-logr/logr v1.4.3 // indirect 27 | github.com/go-openapi/jsonpointer v0.19.6 // indirect 28 | github.com/go-openapi/jsonreference v0.20.2 // indirect 29 | github.com/go-openapi/swag v0.22.4 // indirect 30 | github.com/gogo/protobuf v1.3.2 // indirect 31 | github.com/golang/protobuf v1.5.4 // indirect 32 | github.com/google/gnostic-models v0.6.8 // indirect 33 | github.com/google/go-cmp v0.7.0 // indirect 34 | github.com/google/gofuzz v1.2.0 // indirect 35 | github.com/google/uuid v1.6.0 // indirect 36 | github.com/imdario/mergo v0.3.13 // indirect 37 | github.com/josharian/intern v1.0.0 // indirect 38 | github.com/json-iterator/go v1.1.12 // indirect 39 | github.com/mailru/easyjson v0.7.7 // indirect 40 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 41 | github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect 42 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 43 | github.com/openshift/api v3.9.0+incompatible // indirect 44 | github.com/openshift/client-go v0.0.0-20210521082421-73d9475a9142 // indirect 45 | github.com/spf13/pflag v1.0.5 // indirect 46 | github.com/x448/float16 v0.8.4 // indirect 47 | go.opentelemetry.io/collector/config/configtelemetry v0.116.0 // indirect 48 | go.opentelemetry.io/collector/pipeline v0.116.0 // indirect 49 | go.opentelemetry.io/otel/metric v1.36.0 // indirect 50 | go.opentelemetry.io/otel/trace v1.36.0 // indirect 51 | go.uber.org/multierr v1.11.0 // indirect 52 | golang.org/x/net v0.40.0 // indirect 53 | golang.org/x/oauth2 v0.30.0 // indirect 54 | golang.org/x/sys v0.33.0 // indirect 55 | golang.org/x/term v0.32.0 // indirect 56 | golang.org/x/text v0.25.0 // indirect 57 | golang.org/x/time v0.4.0 // indirect 58 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect 59 | google.golang.org/grpc v1.74.2 // indirect 60 | google.golang.org/protobuf v1.36.6 // indirect 61 | gopkg.in/inf.v0 v0.9.1 // indirect 62 | gopkg.in/yaml.v2 v2.4.0 // indirect 63 | gopkg.in/yaml.v3 v3.0.1 // indirect 64 | k8s.io/klog/v2 v2.130.1 // indirect 65 | k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect 66 | k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect 67 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 68 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect 69 | sigs.k8s.io/yaml v1.4.0 // indirect 70 | ) 71 | 72 | replace github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sdataenricherprocessor/internal => ./internal 73 | -------------------------------------------------------------------------------- /controller/src/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lumigo-io/lumigo-kubernetes-operator 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.8 6 | 7 | require ( 8 | github.com/go-logr/logr v1.4.2 9 | github.com/google/uuid v1.6.0 10 | github.com/onsi/ginkgo/v2 v2.22.0 11 | github.com/onsi/gomega v1.36.1 12 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 13 | gopkg.in/matryer/try.v1 v1.0.0-20150601225556-312d2599e12e 14 | k8s.io/api v0.32.1 15 | k8s.io/apimachinery v0.32.1 16 | k8s.io/client-go v0.32.1 17 | sigs.k8s.io/controller-runtime v0.20.4 18 | ) 19 | 20 | require ( 21 | github.com/beorn7/perks v1.0.1 // indirect 22 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 23 | github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect 24 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 25 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect 26 | github.com/evanphx/json-patch/v5 v5.9.11 // indirect 27 | github.com/fsnotify/fsnotify v1.7.0 // indirect 28 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 29 | github.com/go-logr/zapr v1.3.0 // indirect 30 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 31 | github.com/go-openapi/jsonreference v0.20.2 // indirect 32 | github.com/go-openapi/swag v0.23.0 // indirect 33 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect 34 | github.com/gogo/protobuf v1.3.2 // indirect 35 | github.com/golang/protobuf v1.5.4 // indirect 36 | github.com/google/btree v1.1.3 // indirect 37 | github.com/google/gnostic-models v0.6.8 // indirect 38 | github.com/google/go-cmp v0.6.0 // indirect 39 | github.com/google/gofuzz v1.2.0 // indirect 40 | github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect 41 | github.com/josharian/intern v1.0.0 // indirect 42 | github.com/json-iterator/go v1.1.12 // indirect 43 | github.com/mailru/easyjson v0.7.7 // indirect 44 | github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 // indirect 45 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 46 | github.com/modern-go/reflect2 v1.0.2 // indirect 47 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 48 | github.com/pkg/errors v0.9.1 // indirect 49 | github.com/prometheus/client_golang v1.19.1 // indirect 50 | github.com/prometheus/client_model v0.6.1 // indirect 51 | github.com/prometheus/common v0.55.0 // indirect 52 | github.com/prometheus/procfs v0.15.1 // indirect 53 | github.com/spf13/pflag v1.0.5 // indirect 54 | github.com/x448/float16 v0.8.4 // indirect 55 | go.uber.org/multierr v1.11.0 // indirect 56 | go.uber.org/zap v1.27.0 // indirect 57 | golang.org/x/net v0.38.0 // indirect 58 | golang.org/x/oauth2 v0.27.0 // indirect 59 | golang.org/x/sync v0.12.0 // indirect 60 | golang.org/x/sys v0.31.0 // indirect 61 | golang.org/x/term v0.30.0 // indirect 62 | golang.org/x/text v0.23.0 // indirect 63 | golang.org/x/time v0.7.0 // indirect 64 | golang.org/x/tools v0.26.0 // indirect 65 | gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect 66 | google.golang.org/protobuf v1.35.1 // indirect 67 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 68 | gopkg.in/inf.v0 v0.9.1 // indirect 69 | gopkg.in/yaml.v3 v3.0.1 // indirect 70 | k8s.io/apiextensions-apiserver v0.32.1 // indirect 71 | k8s.io/klog/v2 v2.130.1 // indirect 72 | k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect 73 | k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect 74 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect 75 | sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect 76 | sigs.k8s.io/yaml v1.4.0 // indirect 77 | ) 78 | -------------------------------------------------------------------------------- /telemetryproxy/src/receiver/lumigooperatorheartbeatreceiver/receiver.go: -------------------------------------------------------------------------------- 1 | package lumigooperatorheartbeatreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/lumigooperatorheartbeatreceiver" 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "time" 8 | 9 | "go.opentelemetry.io/collector/component" 10 | "go.opentelemetry.io/collector/consumer" 11 | "go.opentelemetry.io/collector/pdata/pcommon" 12 | "go.opentelemetry.io/collector/pdata/plog" 13 | "go.opentelemetry.io/collector/receiver/receiverhelper" 14 | "go.uber.org/zap" 15 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 | "k8s.io/apimachinery/pkg/runtime/schema" 17 | "k8s.io/client-go/dynamic" 18 | ) 19 | 20 | var ( 21 | lumigoGVR = schema.GroupVersionResource{ 22 | Group: "operator.lumigo.io", 23 | Version: "v1alpha1", 24 | Resource: "lumigoes", 25 | } 26 | namespaceGVR = schema.GroupVersionResource{ 27 | Group: "", 28 | Version: "v1", 29 | Resource: "namespaces", 30 | } 31 | ) 32 | 33 | type lumigooperatorheartbeatReceiver struct { 34 | kube dynamic.Interface 35 | config *Config 36 | consumer consumer.Logs 37 | obsrecv *receiverhelper.ObsReport 38 | ticker *time.Ticker 39 | logger *zap.Logger 40 | } 41 | 42 | func (r *lumigooperatorheartbeatReceiver) Start(ctx context.Context, host component.Host) error { 43 | r.SendUsage(context.TODO()) 44 | r.RunScheduler() 45 | return nil 46 | } 47 | 48 | func (r *lumigooperatorheartbeatReceiver) Shutdown(ctx context.Context) error { 49 | if r.ticker != nil { 50 | r.ticker.Stop() 51 | } 52 | return nil 53 | } 54 | 55 | func (r *lumigooperatorheartbeatReceiver) RunScheduler() { 56 | duration := time.Until(time.Now().Truncate(time.Hour).Add(time.Hour)) 57 | r.ticker = time.NewTicker(duration) 58 | 59 | go func() { 60 | <-r.ticker.C 61 | r.ticker.Reset(time.Hour) 62 | for { 63 | r.logger.Debug("Scheduler running") 64 | if err := r.SendUsage(context.Background()); err != nil { 65 | r.logger.Error("Failed to send heartbeat", zap.Error(err)) 66 | } 67 | <-r.ticker.C 68 | } 69 | }() 70 | } 71 | 72 | func (r *lumigooperatorheartbeatReceiver) SendUsage(ctx context.Context) error { 73 | customResourceList, err := r.kube.Resource(lumigoGVR).Namespace(r.config.Namespace).List(ctx, v1.ListOptions{}) 74 | if err != nil { 75 | return fmt.Errorf("failed to retrieve Lumigo resources: %w", err) 76 | } 77 | 78 | ld := plog.NewLogs() 79 | rl := ld.ResourceLogs().AppendEmpty() 80 | 81 | sl := rl.ScopeLogs().AppendEmpty() 82 | sl.Scope().SetName("lumigo-operator.heartbeat") 83 | 84 | for _, n := range customResourceList.Items { 85 | lumigoResource, err := r.kube.Resource(lumigoGVR).Namespace(r.config.Namespace).Get(ctx, n.GetName(), v1.GetOptions{}) 86 | if err != nil { 87 | return fmt.Errorf("cannot retrieve the '%s' Lumigo resource: %w", n.GetName(), err) 88 | } 89 | 90 | jsonRaw, err := json.Marshal(lumigoResource.UnstructuredContent()) 91 | if err != nil { 92 | return fmt.Errorf("cannot marshal the '%s' Lumigo resource into JSON: %w", n.GetName(), err) 93 | } 94 | 95 | lr := sl.LogRecords().AppendEmpty() 96 | lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) 97 | lr.Body().SetStr(string(jsonRaw)) 98 | } 99 | 100 | opCtx := r.obsrecv.StartLogsOp(context.Background()) 101 | err = r.consumer.ConsumeLogs(opCtx, ld) 102 | r.obsrecv.EndLogsOp(opCtx, "lumigooperatorheartbeat", 1, err) 103 | r.logger.Debug("Lumigo heartbeat sent") 104 | 105 | return nil 106 | } 107 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/target-allocator.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ include "helm.fullname" . }}-target-allocator 5 | namespace: {{ .Release.Namespace }} 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRole 9 | metadata: 10 | name: {{ include "helm.fullname" . }}-target-allocator 11 | rules: 12 | - apiGroups: [""] 13 | resources: ["nodes", "pods", "endpoints", "services"] 14 | verbs: ["get", "list", "watch"] 15 | --- 16 | apiVersion: rbac.authorization.k8s.io/v1 17 | kind: ClusterRoleBinding 18 | metadata: 19 | name: {{ include "helm.fullname" . }}-target-allocator-binding 20 | subjects: 21 | - kind: ServiceAccount 22 | name: {{ include "helm.fullname" . }}-target-allocator 23 | namespace: {{ .Release.Namespace }} 24 | roleRef: 25 | kind: ClusterRole 26 | name: {{ include "helm.fullname" . }}-target-allocator 27 | apiGroup: rbac.authorization.k8s.io 28 | --- 29 | apiVersion: v1 30 | kind: ConfigMap 31 | metadata: 32 | name: {{ include "helm.fullname" . }}-target-allocator-config 33 | namespace: {{ .Release.Namespace }} 34 | data: 35 | target-allocator-config.yaml: 36 | {{ include "targetAllocator.config" . | toYaml | nindent 4 }} 37 | --- 38 | apiVersion: apps/v1 39 | kind: Deployment 40 | metadata: 41 | name: {{ include "helm.fullname" . }}-target-allocator 42 | namespace: {{ .Release.Namespace }} 43 | spec: 44 | replicas: 1 45 | selector: 46 | matchLabels: 47 | app: {{ include "helm.fullname" . }}-target-allocator 48 | template: 49 | metadata: 50 | labels: 51 | app: {{ include "helm.fullname" . }}-target-allocator 52 | annotations: 53 | # This effectively triggers a restart of the Deployment pods when the config changes, which is otherwise not the case for ConfigMaps in k8s. 54 | lumigo.io/ta-config-version: {{ include "targetAllocator.config" . | sha256sum | substr 0 10 | quote }} 55 | spec: 56 | serviceAccountName: {{ include "helm.fullname" . }}-target-allocator 57 | {{- if or .Values.tolerations.targetAllocator .Values.tolerations.global }} 58 | tolerations: 59 | {{- toYaml (.Values.tolerations.targetAllocator | default .Values.tolerations.global) | nindent 6 }} 60 | {{- end }} 61 | {{- if or .Values.nodeSelector.targetAllocator .Values.nodeSelector.global }} 62 | nodeSelector: 63 | {{- toYaml (.Values.nodeSelector.targetAllocator | default .Values.nodeSelector.global) | nindent 8 }} 64 | {{- end }} 65 | containers: 66 | - name: target-allocator 67 | image: "{{ .Values.targetAllocator.image.repository }}:{{ .Values.targetAllocator.image.tag }}" 68 | env: 69 | - name: OTELCOL_NAMESPACE 70 | value: "{{ .Release.Namespace }}" 71 | args: 72 | - "--config-file=/conf/target-allocator-config.yaml" 73 | {{- if .Values.debug.enabled }} 74 | - "--zap-log-level=debug" 75 | {{- end }} 76 | ports: 77 | - containerPort: 80 78 | volumeMounts: 79 | - name: config 80 | mountPath: /conf 81 | volumes: 82 | - name: config 83 | configMap: 84 | name: {{ include "helm.fullname" . }}-target-allocator-config 85 | --- 86 | apiVersion: v1 87 | kind: Service 88 | metadata: 89 | name: {{ include "helm.fullname" . }}-target-allocator 90 | namespace: {{ .Release.Namespace }} 91 | spec: 92 | selector: 93 | app: {{ include "helm.fullname" . }}-target-allocator 94 | ports: 95 | - protocol: TCP 96 | port: 80 97 | targetPort: 8080 -------------------------------------------------------------------------------- /watchdog/src/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lumigo-io/lumigo-kubernetes-operator/watchdog 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.8 6 | 7 | require ( 8 | github.com/go-logr/logr v1.4.2 9 | go.opentelemetry.io/otel v1.35.0 10 | go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.11.0 11 | go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.41.0 12 | go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.11.0 13 | go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 14 | go.opentelemetry.io/otel/log v0.11.0 15 | go.opentelemetry.io/otel/metric v1.35.0 16 | go.opentelemetry.io/otel/sdk v1.35.0 17 | go.opentelemetry.io/otel/sdk/log v0.11.0 18 | go.opentelemetry.io/otel/sdk/metric v1.35.0 19 | golang.org/x/net v0.37.0 20 | k8s.io/api v0.32.1 21 | k8s.io/apimachinery v0.32.1 22 | k8s.io/client-go v0.32.1 23 | k8s.io/metrics v0.26.11 24 | sigs.k8s.io/controller-runtime v0.20.4 25 | ) 26 | 27 | require ( 28 | github.com/cenkalti/backoff/v4 v4.3.0 // indirect 29 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 30 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect 31 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 32 | github.com/go-logr/stdr v1.2.2 // indirect 33 | github.com/go-logr/zapr v1.3.0 // indirect 34 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 35 | github.com/go-openapi/jsonreference v0.20.2 // indirect 36 | github.com/go-openapi/swag v0.23.0 // indirect 37 | github.com/gogo/protobuf v1.3.2 // indirect 38 | github.com/golang/protobuf v1.5.4 // indirect 39 | github.com/google/gnostic-models v0.6.8 // indirect 40 | github.com/google/go-cmp v0.7.0 // indirect 41 | github.com/google/gofuzz v1.2.0 // indirect 42 | github.com/google/uuid v1.6.0 // indirect 43 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect 44 | github.com/josharian/intern v1.0.0 // indirect 45 | github.com/json-iterator/go v1.1.12 // indirect 46 | github.com/mailru/easyjson v0.7.7 // indirect 47 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 48 | github.com/modern-go/reflect2 v1.0.2 // indirect 49 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 50 | github.com/pkg/errors v0.9.1 // indirect 51 | github.com/spf13/pflag v1.0.5 // indirect 52 | github.com/x448/float16 v0.8.4 // indirect 53 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 54 | go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.41.0 // indirect 55 | go.opentelemetry.io/otel/trace v1.35.0 // indirect 56 | go.opentelemetry.io/proto/otlp v1.5.0 // indirect 57 | go.uber.org/multierr v1.11.0 // indirect 58 | go.uber.org/zap v1.27.0 // indirect 59 | golang.org/x/oauth2 v0.27.0 // indirect 60 | golang.org/x/sys v0.31.0 // indirect 61 | golang.org/x/term v0.30.0 // indirect 62 | golang.org/x/text v0.23.0 // indirect 63 | golang.org/x/time v0.7.0 // indirect 64 | google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect 65 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect 66 | google.golang.org/grpc v1.71.1 // indirect 67 | google.golang.org/protobuf v1.36.6 // indirect 68 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 69 | gopkg.in/inf.v0 v0.9.1 // indirect 70 | gopkg.in/yaml.v3 v3.0.1 // indirect 71 | k8s.io/klog/v2 v2.130.1 // indirect 72 | k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect 73 | k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect 74 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect 75 | sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect 76 | sigs.k8s.io/yaml v1.4.0 // indirect 77 | ) 78 | -------------------------------------------------------------------------------- /charts/lumigo-operator/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | {{- $coloredOutput := and .Values.output.color (eq .Values.output.color true) -}} 2 | 3 | {{- if and .Release.IsInstall }} 4 | Thank you for installing the {{ include "highlight" (list "Lumigo" "red" $coloredOutput) }} operator. 5 | 6 | Your release is named '{{ .Release.Name }}', and your Lumigo operator is running in the '{{ include "highlight" (list .Release.Namespace "cyan" $coloredOutput) }}' namespace. 7 | {{- else }} 8 | Your {{ include "highlight" (list "Lumigo" "red" $coloredOutput) }} operator is upgraded. 9 | {{- end }} 10 | 11 | {{ include "highlight" (list "# Your Lumigo operator" "cyan" $coloredOutput) }} 12 | 13 | To see the {{ include "highlight" (list "status" "cyan" $coloredOutput) }} of your operator, run: 14 | 15 | $ kubectl get deployment {{ include "helm.fullname" . }}-controller-manager -o wide --namespace {{ .Release.Namespace }} 16 | 17 | {{- if and .Release.IsUpgrade .Values.output.showOperatorStatus }} 18 | {{- $lumigoes := (lookup "operator.lumigo.io/v1alpha1" "Lumigo" "" "").items }} 19 | {{- $lumigo_statuses := dict }} 20 | {{- if not (empty $lumigoes) }} 21 | {{- range $index, $lumigo := $lumigoes }} 22 | {{- $_ := set $lumigo_statuses $lumigo.metadata.namespace (include "lumigo.error" $lumigo) }} 23 | {{- end }} 24 | {{- end }} 25 | {{ if (empty (keys $lumigo_statuses)) }} 26 | None of your namespaces are currently monitored by the Lumigo operator. 27 | {{- else }} 28 | The Lumigo operator currently monitors the following namespaces: 29 | 30 | {{- range $index, $namespace := (keys $lumigo_statuses) }} 31 | {{ $lumigoError := get $lumigo_statuses $namespace }} 32 | {{- if $lumigoError -}} 33 | {{- if $coloredOutput -}} 34 | * {{ include "highlight" (list $namespace "red" $coloredOutput) }}: {{ print $lumigoError }} 35 | {{- else }} 36 | * {{ print $namespace }}: [ERROR] {{ print $lumigoError }} 37 | {{- end }} 38 | {{- else }} 39 | * {{ include "highlight" (list $namespace "green" $coloredOutput) }} 40 | {{- end }} 41 | {{- end }} 42 | 43 | The list of currently injected resources can be retrieved with: 44 | 45 | $ kubectl get all -A --selector=lumigo.auto-trace 46 | {{- end }} 47 | {{- end }} 48 | 49 | {{ include "highlight" (list "# Next steps" "cyan" $coloredOutput) }} 50 | 51 | To {{ include "highlight" (list "monitor" "cyan" $coloredOutput) }} applications in a namespace with the Lumigo operator: 52 | 53 | 1. create a secret with a {{ include "highlight" (list "Lumigo token" "red" $coloredOutput) }} in that namespace: 54 | 55 | $ kubectl create secret generic --namespace {{ include "highlight" (list "" "red" $coloredOutput) }} lumigo-credentials --from-literal token={{ include "highlight" (list "" "red" $coloredOutput) }} 56 | 57 | To retrieve your Lumigo token, refer to: https://docs.lumigo.io/docs/lumigo-tokens. 58 | 59 | 2. create a {{ include "highlight" (list "'Lumigo' resource" "orange" $coloredOutput) }} in that namespace: 60 | 61 | $ echo '{ 62 | "apiVersion": "operator.lumigo.io/v1alpha1", 63 | "kind": "Lumigo", 64 | "metadata": { 65 | "name": "lumigo" 66 | }, 67 | "spec": { 68 | "lumigoToken": { 69 | "secretRef": { 70 | "name": "lumigo-credentials", 71 | "key": "token" 72 | } 73 | } 74 | } 75 | }' | kubectl apply -f - --namespace {{ include "highlight" (list "" "red" $coloredOutput) }} 76 | 77 | For more information on how to configure the Lumigo operator, refer to: https://github.com/lumigo-io/lumigo-kubernetes-operator 78 | {{- if $coloredOutput }} 79 | 80 | {{ print "(To turn off ANSI colors in the output, set the 'output.color' value to 'false')" }} 81 | {{- end }} -------------------------------------------------------------------------------- /.github/workflows/discover_new_versions.yaml: -------------------------------------------------------------------------------- 1 | name: discover new kube-rbac-proxy versions 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: {} # Manual trigger for testing and schedule override 7 | 8 | jobs: 9 | update-kube-rbac-proxy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v3 14 | - id: check-latest-version-brancz-kube-rbac-proxy 15 | name: Check latest version of brancz/kube-rbac-proxy 16 | uses: mmanciop/check-latest-versions@v2 17 | with: 18 | package-manager: github-releases 19 | package-name: 'brancz/kube-rbac-proxy' 20 | - id: check-latest-version-brancz-kube-rbac-proxy-base-image 21 | name: Check latest version of the brancz/kube-rbac-proxy base image 22 | run: | 23 | docker pull gcr.io/distroless/static:nonroot 24 | version=$(docker image inspect --format='{{index .RepoDigests 0}}' gcr.io/distroless/static:nonroot | cut -d '@' -f 2) 25 | echo "::set-output name=version::$version" 26 | - name: Check version file updates 27 | id: verify 28 | run: | 29 | if [ "${{ steps.check-latest-version-brancz-kube-rbac-proxy.outputs.version }}" != $(< kube-rbac-proxy/VERSION.kube-rbac-proxy) ]; then 30 | echo 'kube-rbac-proxy=true' >> $GITHUB_OUTPUT 31 | echo 'update=true' >> $GITHUB_OUTPUT 32 | fi 33 | if [ "${{ steps.check-latest-version-brancz-kube-rbac-proxy-base-image.outputs.version }}" != $(< kube-rbac-proxy/VERSION.base-image) ]; then 34 | echo 'base-image=true' >> $GITHUB_OUTPUT 35 | echo 'update=true' >> $GITHUB_OUTPUT 36 | fi 37 | echo 'branch-name=kube-rbac-proxy-update' >> $GITHUB_OUTPUT 38 | - name: Set Git config up 39 | run: | 40 | git config --global user.name "Lumigo Bot" 41 | git config --global user.email "bot@lumigo.io" 42 | - name: Create update commit for kube-rbac-proxy 43 | if: steps.verify.outputs.kube-rbac-proxy 44 | run: | 45 | echo -n "${{ steps.check-latest-version-brancz-kube-rbac-proxy.outputs.version }}" > kube-rbac-proxy/VERSION.kube-rbac-proxy 46 | git add 'kube-rbac-proxy/VERSION.kube-rbac-proxy' 47 | git commit -m 'Update the kube-rbac-proxy to version ${{ steps.check-latest-version-brancz-kube-rbac-proxy.outputs.version }}' 48 | git push --force origin HEAD:${{ steps.verify.outputs.branch-name }} 49 | - name: Create update commit for kube-rbac-proxy base-image 50 | if: steps.verify.outputs.base-image 51 | run: | 52 | echo -n "${{ steps.check-latest-version-brancz-kube-rbac-proxy-base-image.outputs.version }}" > kube-rbac-proxy/VERSION.base-image 53 | git add 'kube-rbac-proxy/VERSION.base-image' 54 | git commit -m 'Update the kube-rbac-proxy base image to version ${{ steps.check-latest-version-brancz-kube-rbac-proxy-base-image.outputs.version }}' 55 | git push --force origin HEAD:${{ steps.verify.outputs.branch-name }} 56 | - name: Open kube-proxy-rbac-update Pull Request 57 | id: open-kube-proxy-rbac-update-pr 58 | if: steps.verify.outputs.update 59 | continue-on-error: true 60 | uses: mmanciop/pull-request@master 61 | with: 62 | source_branch: '${{ steps.verify.outputs.branch-name }}' 63 | destination_branch: 'main' 64 | pr_title: 'chore: New kube-proxy-rbac Version' 65 | pr_body: 'Automated kube-proxy-rbac update Pull Request :crown:' 66 | pr_draft: false 67 | pr_allow_empty: false 68 | pr_automerge: true 69 | github_token: ${{ secrets.GITHUB_TOKEN }} 70 | pr_reviewer: GuyMoses,nadav3396 -------------------------------------------------------------------------------- /images/lumigo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /watchdog/src/watchers/watchdog_k8s_context.go: -------------------------------------------------------------------------------- 1 | package watchers 2 | 3 | import ( 4 | "context" 5 | "path/filepath" 6 | 7 | "github.com/go-logr/logr" 8 | "github.com/lumigo-io/lumigo-kubernetes-operator/watchdog/config" 9 | "go.opentelemetry.io/otel/attribute" 10 | "go.opentelemetry.io/otel/sdk/resource" 11 | semconv "go.opentelemetry.io/otel/semconv/v1.17.0" 12 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 | "k8s.io/client-go/kubernetes" 14 | "k8s.io/client-go/rest" 15 | "k8s.io/client-go/tools/clientcmd" 16 | "k8s.io/client-go/util/homedir" 17 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 18 | ) 19 | 20 | type watchdogContext struct { 21 | CloudProvider string 22 | ClusterUid string 23 | NamespaceUID string 24 | ClusterK8sVersion string 25 | Clientset *kubernetes.Clientset 26 | K8sConfig *rest.Config 27 | OtelResource *resource.Resource 28 | Logger logr.Logger 29 | } 30 | 31 | func getK8SVersion(clientset *kubernetes.Clientset) string { 32 | version, err := clientset.ServerVersion() 33 | if err != nil { 34 | return "unknown" 35 | } 36 | 37 | return version.String() 38 | } 39 | 40 | func getK8SCloudProvider(ctx context.Context, clientset *kubernetes.Clientset) string { 41 | nodeList, err := clientset.CoreV1().Nodes().List(ctx, v1.ListOptions{}) 42 | if err != nil { 43 | return "unknown" 44 | } 45 | 46 | provider := nodeList.Items[0].Spec.ProviderID 47 | if provider == "" { 48 | return "unknown" 49 | } 50 | 51 | return provider 52 | } 53 | 54 | func getClusterUid(ctx context.Context, clientset *kubernetes.Clientset) (string, error) { 55 | ns, err := clientset.CoreV1().Namespaces().Get(ctx, "kube-system", v1.GetOptions{}) 56 | if err != nil { 57 | return "", err 58 | } 59 | 60 | return string(ns.GetUID()), nil 61 | } 62 | 63 | func getK8sConfig() (*rest.Config, error) { 64 | k8sConfig, err := clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config")) 65 | if err != nil { 66 | k8sConfig, err = rest.InClusterConfig() 67 | if err != nil { 68 | return nil, err 69 | } 70 | } 71 | return k8sConfig, nil 72 | } 73 | 74 | func getK8sClient(k8sConfig *rest.Config) (*kubernetes.Clientset, error) { 75 | clientset, err := kubernetes.NewForConfig(k8sConfig) 76 | if err != nil { 77 | return nil, err 78 | } 79 | return clientset, nil 80 | } 81 | 82 | func getNamespaceUid(ctx context.Context, clientset *kubernetes.Clientset, namespace string) (string, error) { 83 | ns, err := clientset.CoreV1().Namespaces().Get(ctx, namespace, v1.GetOptions{}) 84 | if err != nil { 85 | return "", err 86 | } 87 | return string(ns.GetUID()), nil 88 | } 89 | 90 | func NewWatchdogK8sContext(ctx context.Context, config *config.Config) (*watchdogContext, error) { 91 | k8sConfig, err := getK8sConfig() 92 | 93 | if err != nil { 94 | return nil, err 95 | } 96 | clientset, err := getK8sClient(k8sConfig) 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | clusterUID, err := getClusterUid(ctx, clientset) 102 | if err != nil { 103 | return nil, err 104 | } 105 | 106 | namespaceUID, err := getNamespaceUid(ctx, clientset, config.LumigoOperatorNamespace) 107 | if err != nil { 108 | return nil, err 109 | } 110 | 111 | cloudProvider := getK8SCloudProvider(ctx, clientset) 112 | if err != nil { 113 | return nil, err 114 | } 115 | 116 | clusterK8sVersion := getK8SVersion(clientset) 117 | 118 | logger := zap.New().WithName("watchdog") 119 | 120 | otelResource := resource.NewWithAttributes( 121 | semconv.SchemaURL, 122 | semconv.ServiceName("lumigo-kubernetes-operator-watchdog"), 123 | attribute.String("lumigo.k8s_operator.version", config.LumigoOperatorVersion), 124 | attribute.String("k8s.cluster.version", clusterK8sVersion), 125 | attribute.String("k8s.namespace.name", config.LumigoOperatorNamespace), 126 | attribute.String("k8s.cluster.uid", clusterUID), 127 | attribute.String("k8s.cluster.name", config.ClusterName), 128 | attribute.String("k8s.namespace.uid", namespaceUID), 129 | ) 130 | 131 | return &watchdogContext{ 132 | K8sConfig: k8sConfig, 133 | Clientset: clientset, 134 | CloudProvider: cloudProvider, 135 | ClusterUid: clusterUID, 136 | NamespaceUID: namespaceUID, 137 | ClusterK8sVersion: clusterK8sVersion, 138 | OtelResource: otelResource, 139 | Logger: logger, 140 | }, nil 141 | } 142 | -------------------------------------------------------------------------------- /controller/src/api/v1alpha1/lumigo_webhook_suite_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 Lumigo. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | "context" 21 | "crypto/tls" 22 | "fmt" 23 | "net" 24 | "path/filepath" 25 | "testing" 26 | "time" 27 | 28 | . "github.com/onsi/ginkgo/v2" 29 | . "github.com/onsi/gomega" 30 | 31 | admissionv1beta1 "k8s.io/api/admission/v1beta1" 32 | //+kubebuilder:scaffold:imports 33 | "k8s.io/apimachinery/pkg/runtime" 34 | "k8s.io/client-go/rest" 35 | ctrl "sigs.k8s.io/controller-runtime" 36 | "sigs.k8s.io/controller-runtime/pkg/client" 37 | "sigs.k8s.io/controller-runtime/pkg/envtest" 38 | logf "sigs.k8s.io/controller-runtime/pkg/log" 39 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 40 | "sigs.k8s.io/controller-runtime/pkg/metrics/server" 41 | "sigs.k8s.io/controller-runtime/pkg/webhook" 42 | ) 43 | 44 | // These tests use Ginkgo (BDD-style Go testing framework). Refer to 45 | // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 46 | 47 | var cfg *rest.Config 48 | var k8sClient client.Client 49 | var testEnv *envtest.Environment 50 | var ctx context.Context 51 | var cancel context.CancelFunc 52 | 53 | func TestAPIs(t *testing.T) { 54 | RegisterFailHandler(Fail) 55 | 56 | RunSpecs(t, "Webhook Suite") 57 | } 58 | 59 | var _ = BeforeSuite(func() { 60 | logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) 61 | 62 | ctx, cancel = context.WithCancel(context.TODO()) 63 | 64 | By("bootstrapping test environment") 65 | testEnv = &envtest.Environment{ 66 | CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "config", "crd", "bases")}, 67 | ErrorIfCRDPathMissing: true, 68 | WebhookInstallOptions: envtest.WebhookInstallOptions{ 69 | Paths: []string{filepath.Join("..", "..", "config", "webhook")}, 70 | }, 71 | } 72 | 73 | var err error 74 | // cfg is defined in this file globally. 75 | cfg, err = testEnv.Start() 76 | Expect(err).NotTo(HaveOccurred()) 77 | Expect(cfg).NotTo(BeNil()) 78 | 79 | scheme := runtime.NewScheme() 80 | err = AddToScheme(scheme) 81 | Expect(err).NotTo(HaveOccurred()) 82 | 83 | err = admissionv1beta1.AddToScheme(scheme) 84 | Expect(err).NotTo(HaveOccurred()) 85 | 86 | //+kubebuilder:scaffold:scheme 87 | 88 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme}) 89 | Expect(err).NotTo(HaveOccurred()) 90 | Expect(k8sClient).NotTo(BeNil()) 91 | 92 | // start webhook server using Manager 93 | webhookInstallOptions := &testEnv.WebhookInstallOptions 94 | mgr, err := ctrl.NewManager(cfg, ctrl.Options{ 95 | Scheme: scheme, 96 | WebhookServer: webhook.NewServer(webhook.Options{ 97 | Host: webhookInstallOptions.LocalServingHost, 98 | Port: webhookInstallOptions.LocalServingPort, 99 | CertDir: webhookInstallOptions.LocalServingCertDir, 100 | }), 101 | LeaderElection: false, 102 | Metrics: server.Options{BindAddress: "0"}, 103 | }) 104 | Expect(err).NotTo(HaveOccurred()) 105 | 106 | err = (&Lumigo{}).SetupWebhookWithManager(mgr) 107 | Expect(err).NotTo(HaveOccurred()) 108 | 109 | //+kubebuilder:scaffold:webhook 110 | 111 | go func() { 112 | defer GinkgoRecover() 113 | err = mgr.Start(ctx) 114 | Expect(err).NotTo(HaveOccurred()) 115 | }() 116 | 117 | // wait for the webhook server to get ready 118 | dialer := &net.Dialer{Timeout: time.Second} 119 | addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort) 120 | Eventually(func() error { 121 | conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true}) 122 | if err != nil { 123 | return err 124 | } 125 | conn.Close() 126 | return nil 127 | }).Should(Succeed()) 128 | 129 | }) 130 | 131 | var _ = AfterSuite(func() { 132 | cancel() 133 | By("tearing down the test environment") 134 | err := testEnv.Stop() 135 | Expect(err).NotTo(HaveOccurred()) 136 | }) 137 | -------------------------------------------------------------------------------- /tests/kubernetes-distros/kind/apps/client/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lumigo-js-test-client", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "lumigo-js-test-client", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@opentelemetry/api": "^1.4.1", 13 | "axios": "^1.1.2" 14 | } 15 | }, 16 | "node_modules/@opentelemetry/api": { 17 | "version": "1.4.1", 18 | "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz", 19 | "integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==", 20 | "engines": { 21 | "node": ">=8.0.0" 22 | } 23 | }, 24 | "node_modules/asynckit": { 25 | "version": "0.4.0", 26 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 27 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 28 | }, 29 | "node_modules/axios": { 30 | "version": "1.4.0", 31 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", 32 | "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", 33 | "dependencies": { 34 | "follow-redirects": "^1.15.0", 35 | "form-data": "^4.0.0", 36 | "proxy-from-env": "^1.1.0" 37 | } 38 | }, 39 | "node_modules/combined-stream": { 40 | "version": "1.0.8", 41 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 42 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 43 | "dependencies": { 44 | "delayed-stream": "~1.0.0" 45 | }, 46 | "engines": { 47 | "node": ">= 0.8" 48 | } 49 | }, 50 | "node_modules/delayed-stream": { 51 | "version": "1.0.0", 52 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 53 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 54 | "engines": { 55 | "node": ">=0.4.0" 56 | } 57 | }, 58 | "node_modules/follow-redirects": { 59 | "version": "1.15.2", 60 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", 61 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", 62 | "funding": [ 63 | { 64 | "type": "individual", 65 | "url": "https://github.com/sponsors/RubenVerborgh" 66 | } 67 | ], 68 | "engines": { 69 | "node": ">=4.0" 70 | }, 71 | "peerDependenciesMeta": { 72 | "debug": { 73 | "optional": true 74 | } 75 | } 76 | }, 77 | "node_modules/form-data": { 78 | "version": "4.0.0", 79 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 80 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 81 | "dependencies": { 82 | "asynckit": "^0.4.0", 83 | "combined-stream": "^1.0.8", 84 | "mime-types": "^2.1.12" 85 | }, 86 | "engines": { 87 | "node": ">= 6" 88 | } 89 | }, 90 | "node_modules/mime-db": { 91 | "version": "1.52.0", 92 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 93 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 94 | "engines": { 95 | "node": ">= 0.6" 96 | } 97 | }, 98 | "node_modules/mime-types": { 99 | "version": "2.1.35", 100 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 101 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 102 | "dependencies": { 103 | "mime-db": "1.52.0" 104 | }, 105 | "engines": { 106 | "node": ">= 0.6" 107 | } 108 | }, 109 | "node_modules/proxy-from-env": { 110 | "version": "1.1.0", 111 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 112 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 113 | } 114 | } 115 | } 116 | --------------------------------------------------------------------------------