├── CODEOWNERS ├── pkg ├── injection │ ├── codemodule │ │ └── installer │ │ │ ├── image │ │ │ ├── unpack_test.go │ │ │ └── config.go │ │ │ ├── installer.go │ │ │ ├── job │ │ │ └── config.go │ │ │ ├── common │ │ │ └── consts.go │ │ │ ├── url │ │ │ ├── config.go │ │ │ └── unpack.go │ │ │ ├── symlink │ │ │ └── config.go │ │ │ └── zip │ │ │ ├── config.go │ │ │ └── zip_test.go │ └── namespace │ │ ├── bootstrapperconfig │ │ ├── conditions.go │ │ └── config.go │ │ └── mapper │ │ └── config.go ├── controllers │ ├── dynakube │ │ ├── extension │ │ │ ├── tls │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ ├── eec │ │ │ │ ├── conditions.go │ │ │ │ ├── config.go │ │ │ │ └── reconciler_integration_test.go │ │ │ ├── conditions.go │ │ │ ├── databases │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ ├── config.go │ │ │ └── consts │ │ │ │ └── consts.go │ │ ├── dtpullsecret │ │ │ ├── conditions.go │ │ │ └── config.go │ │ ├── kspm │ │ │ ├── token │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ ├── daemonset │ │ │ │ ├── conditions.go │ │ │ │ ├── config.go │ │ │ │ └── certs_test.go │ │ │ └── config.go │ │ ├── activegate │ │ │ ├── internal │ │ │ │ ├── tls │ │ │ │ │ ├── conditions.go │ │ │ │ │ └── config.go │ │ │ │ ├── statefulset │ │ │ │ │ ├── conditions.go │ │ │ │ │ ├── config.go │ │ │ │ │ └── builder │ │ │ │ │ │ ├── builder.go │ │ │ │ │ │ └── modifiers │ │ │ │ │ │ └── authtoken_test.go │ │ │ │ ├── customproperties │ │ │ │ │ ├── conditions.go │ │ │ │ │ └── config.go │ │ │ │ ├── capability │ │ │ │ │ └── config.go │ │ │ │ └── authtoken │ │ │ │ │ ├── config.go │ │ │ │ │ └── conditions.go │ │ │ ├── iface.go │ │ │ └── config.go │ │ ├── k8sentity │ │ │ ├── conditions.go │ │ │ └── config.go │ │ ├── otelc │ │ │ ├── service │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ ├── statefulset │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ ├── configuration │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ ├── endpoint │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ ├── config.go │ │ │ ├── activegate │ │ │ │ └── service.go │ │ │ └── consts │ │ │ │ └── consts.go │ │ ├── metadata │ │ │ └── rules │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ ├── logmonitoring │ │ │ ├── daemonset │ │ │ │ ├── conditions.go │ │ │ │ ├── config.go │ │ │ │ └── annotations.go │ │ │ ├── configsecret │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ └── logmonsettings │ │ │ │ └── config.go │ │ ├── connectioninfo │ │ │ ├── activegate │ │ │ │ ├── conditions.go │ │ │ │ └── config.go │ │ │ └── oneagent │ │ │ │ ├── config.go │ │ │ │ ├── conditions.go │ │ │ │ └── communication_hosts.go │ │ ├── token │ │ │ └── config.go │ │ ├── proxy │ │ │ ├── config.go │ │ │ ├── volumes.go │ │ │ └── consts.go │ │ ├── config.go │ │ ├── oneagent │ │ │ ├── config.go │ │ │ ├── daemonset │ │ │ │ ├── config.go │ │ │ │ └── affinity.go │ │ │ └── error_handler.go │ │ ├── version │ │ │ └── config.go │ │ ├── injection │ │ │ └── config.go │ │ ├── apimonitoring │ │ │ └── config.go │ │ ├── istio │ │ │ └── config.go │ │ ├── dynatraceapi │ │ │ └── status.go │ │ └── deploymentmetadata │ │ │ └── config.go │ ├── reconciler.go │ ├── csi │ │ ├── metadata │ │ │ └── config.go │ │ ├── provisioner │ │ │ ├── cleanup │ │ │ │ └── config.go │ │ │ ├── config.go │ │ │ └── install_test.go │ │ └── driver │ │ │ ├── volumes │ │ │ ├── host │ │ │ │ └── config.go │ │ │ ├── publisher.go │ │ │ └── app │ │ │ │ └── config.go │ │ │ └── config.go │ ├── edgeconnect │ │ ├── config.go │ │ ├── secret │ │ │ └── config.go │ │ ├── version │ │ │ ├── config.go │ │ │ └── iface.go │ │ └── deployment │ │ │ └── config.go │ ├── certificates │ │ └── config.go │ └── nodes │ │ └── config.go ├── consts │ ├── host_availability.go │ ├── otlp.go │ ├── agent_injection.go │ ├── tls.go │ └── extensions.go ├── api │ ├── v1alpha2 │ │ └── edgeconnect │ │ │ ├── config.go │ │ │ ├── conversion.go │ │ │ ├── edgeconnect_webhook.go │ │ │ ├── certs.go │ │ │ └── edgeconnect_types_test.go │ ├── latest │ │ └── dynakube │ │ │ ├── conversion.go │ │ │ ├── metadataenrichment │ │ │ ├── status.go │ │ │ └── props.go │ │ │ ├── logmonitoring │ │ │ └── ingestrulematchers.go │ │ │ ├── telemetryservice_props.go │ │ │ ├── metadata_enrichment_props.go │ │ │ ├── otlpexporterconfiguration_props.go │ │ │ ├── dynakube_webhook.go │ │ │ ├── kspm_props.go │ │ │ ├── logmonitoring_props.go │ │ │ ├── oneagent_props.go │ │ │ ├── telemetryingest │ │ │ └── spec.go │ │ │ ├── otelc_props.go │ │ │ ├── activegate_props.go │ │ │ ├── kspm │ │ │ └── props.go │ │ │ ├── extensions_props.go │ │ │ └── activegate │ │ │ └── status.go │ ├── validation │ │ ├── edgeconnect │ │ │ ├── config.go │ │ │ ├── module.go │ │ │ ├── service_account.go │ │ │ ├── host_patterns.go │ │ │ ├── webhook.go │ │ │ ├── automation_validation.go │ │ │ ├── module_test.go │ │ │ └── name.go │ │ ├── dynakube │ │ │ ├── preview.go │ │ │ ├── config.go │ │ │ ├── istio_test.go │ │ │ ├── preview_test.go │ │ │ ├── extensions.go │ │ │ ├── istio.go │ │ │ ├── featureflag.go │ │ │ └── webhook.go │ │ └── message.go │ ├── consts.go │ ├── status │ │ └── phase.go │ ├── v1beta3 │ │ └── dynakube │ │ │ ├── logmonitoring │ │ │ └── ingestrulematchers.go │ │ │ ├── kspm │ │ │ └── props.go │ │ │ ├── metadata_enrichment_props.go │ │ │ ├── dynakube_webhook.go │ │ │ ├── kspm_props.go │ │ │ ├── oneagent_props.go │ │ │ ├── logmonitoring_props.go │ │ │ ├── activegate_props.go │ │ │ └── metada_enrichment.go │ ├── v1beta4 │ │ └── dynakube │ │ │ ├── logmonitoring │ │ │ └── ingestrulematchers.go │ │ │ ├── telemetryservice_props.go │ │ │ ├── kspm │ │ │ └── props.go │ │ │ ├── metadata_enrichment_props.go │ │ │ ├── dynakube_webhook.go │ │ │ ├── kspm_props.go │ │ │ ├── logmonitoring_props.go │ │ │ ├── oneagent_props.go │ │ │ ├── telemetryingest │ │ │ └── spec.go │ │ │ ├── otelc_props.go │ │ │ ├── activegate_props.go │ │ │ └── metada_enrichment.go │ ├── v1beta5 │ │ └── dynakube │ │ │ ├── logmonitoring │ │ │ └── ingestrulematchers.go │ │ │ ├── telemetryservice_props.go │ │ │ ├── metadata_enrichment_props.go │ │ │ ├── dynakube_webhook.go │ │ │ ├── kspm_props.go │ │ │ ├── logmonitoring_props.go │ │ │ ├── oneagent_props.go │ │ │ ├── telemetryingest │ │ │ └── spec.go │ │ │ ├── otelc_props.go │ │ │ ├── extensions_props.go │ │ │ ├── activegate_props.go │ │ │ ├── kspm │ │ │ └── props.go │ │ │ └── metada_enrichment.go │ ├── exp │ │ └── otlp.go │ ├── v1alpha1 │ │ └── edgeconnect │ │ │ └── edgeconnect_webhook.go │ └── shared │ │ ├── communication │ │ └── types.go │ │ ├── value │ │ └── types.go │ │ └── proxy │ │ └── types.go ├── util │ ├── builder │ │ └── mocks │ │ │ └── data.go │ ├── kubesystem │ │ ├── execution_env.go │ │ └── kubesystem.go │ ├── kubernetes │ │ ├── objects │ │ │ ├── k8sstatefulset │ │ │ │ └── consts.go │ │ │ ├── k8sevent │ │ │ │ └── event.go │ │ │ ├── k8ssecret │ │ │ │ └── tokens_test.go │ │ │ └── k8spod │ │ │ │ └── pod.go │ │ └── fields │ │ │ ├── k8sresource │ │ │ └── resources.go │ │ │ └── k8svolume │ │ │ └── volumes.go │ ├── functional │ │ ├── map.go │ │ ├── filter.go │ │ └── map_test.go │ ├── projectpath │ │ └── projectpath.go │ ├── envvars │ │ └── envvars.go │ ├── conditions │ │ ├── token.go │ │ ├── suffix.go │ │ ├── error_test.go │ │ ├── status.go │ │ └── time.go │ ├── prioritymap │ │ └── cmdline_parser.go │ ├── eventfilter │ │ └── eventfilter.go │ ├── oneagentapm │ │ └── oneagentapm.go │ └── map │ │ └── map.go ├── arch │ ├── amd64.go │ ├── arm64.go │ ├── s390x.go │ ├── ppc64le.go │ └── consts.go ├── webhook │ ├── mutation │ │ ├── pod │ │ │ ├── mutator │ │ │ │ ├── otlp │ │ │ │ │ └── exporter │ │ │ │ │ │ └── config.go │ │ │ │ ├── errors.go │ │ │ │ ├── metadata │ │ │ │ │ └── deprecated.go │ │ │ │ ├── container.go │ │ │ │ ├── container_test.go │ │ │ │ └── interface.go │ │ │ ├── handler │ │ │ │ ├── interface.go │ │ │ │ ├── otlp │ │ │ │ │ └── config.go │ │ │ │ └── injection │ │ │ │ │ ├── deprecated.go │ │ │ │ │ ├── config.go │ │ │ │ │ └── deprecated_test.go │ │ │ ├── arg │ │ │ │ └── arg.go │ │ │ └── annotations │ │ │ │ └── annotations.go │ │ └── namespace │ │ │ └── config.go │ └── config.go ├── otlp │ └── exporterconfig │ │ ├── conditions.go │ │ ├── config.go │ │ └── replicate.go ├── clients │ ├── dynatrace │ │ ├── config.go │ │ └── activegate_version.go │ ├── utils │ │ ├── http.go │ │ └── http_test.go │ └── edgeconnect │ │ └── endpoints.go ├── oci │ └── dockerkeychain │ │ └── config.go └── otelcgen │ ├── testdata │ ├── extensions_only.yaml │ ├── exporters_only.yaml │ ├── receivers_zipkin_only.yaml │ ├── services_zipkin_only.yaml │ ├── services_statsd_only.yaml │ ├── receivers_otlp_only.yaml │ ├── receivers_statsd.yaml │ └── receivers_jaeger_only.yaml │ ├── consts.go │ ├── extensions.go │ ├── processors_test.go │ ├── extensions_test.go │ ├── exporters_test.go │ └── exporters.go ├── .github ├── codeql │ └── codeql-config.yml ├── release.yml ├── workflows │ └── e2e-cleanup-kubernetes-settings.yaml └── pre-commit ├── hack ├── build │ ├── bin │ │ ├── entrypoint │ │ └── user_setup │ ├── ci │ │ ├── sanitize-branch-name.sh │ │ ├── third-party-licenses.sh │ │ ├── push-helm-chart.sh │ │ ├── update-e2e-ondemand-pipeline.py │ │ ├── check-image-available.sh │ │ ├── generate-new-helm-index-yaml.sh │ │ ├── update-renovate-json5.py │ │ └── generate-helm-package.sh │ ├── create_go_build_tags.sh │ ├── push_image.sh │ ├── command.sh │ └── create_go_linker_args.sh ├── requirements.txt ├── make │ ├── kind.mk │ ├── tests │ │ ├── olm.mk │ │ └── helm.mk │ ├── deploy │ │ └── cleanup.mk │ ├── manifests │ │ └── manifests.mk │ ├── markdown.mk │ ├── helm │ │ └── version.mk │ └── doc.mk ├── helm │ ├── test.sh │ └── lint.sh ├── gcr │ ├── deployer-image.sh │ └── deploy.sh ├── do_env_variables_exist.sh ├── kind │ └── cluster.yaml └── boilerplate.go.txt ├── config ├── manifests │ └── kustomization.yaml ├── crd │ ├── bases │ │ └── kustomization.yaml │ ├── kustomization.yaml │ └── patches │ │ ├── webhook_in_dynakubes.yaml │ │ └── webhook_in_edgeconnects.yaml ├── helm │ ├── chart │ │ └── default │ │ │ ├── logo.png │ │ │ ├── templates │ │ │ ├── Common │ │ │ │ ├── extensions │ │ │ │ │ └── database │ │ │ │ │ │ └── service-account-database.yaml │ │ │ │ ├── webhook │ │ │ │ │ ├── poddisruptionbudget-webhook.yaml │ │ │ │ │ └── serviceaccount-webhook.yaml │ │ │ │ ├── operator │ │ │ │ │ └── serviceaccount-operator.yaml │ │ │ │ └── csi │ │ │ │ │ └── serviceaccount-csi.yaml │ │ │ └── NOTES.txt │ │ │ ├── app-readme.md │ │ │ ├── .helmignore │ │ │ └── tests │ │ │ ├── Common │ │ │ ├── edgeconnect │ │ │ │ └── serviceaccount-edgeconnect_test.yaml │ │ │ ├── operator │ │ │ │ ├── allowlistsynchronizer_test.yaml │ │ │ │ └── serviceaccount-operator_test.yaml │ │ │ ├── webhook │ │ │ │ ├── poddisruptionbudget-webhook_test.yaml │ │ │ │ └── serviceaccount-webhook_test.yaml │ │ │ └── activegate │ │ │ │ └── serviceaccount-activegate_test.yaml │ │ │ └── Google │ │ │ └── application_test.yaml │ ├── repos │ │ └── stable │ │ │ ├── dynatrace-operator-0.10.0.tgz │ │ │ ├── dynatrace-operator-0.10.1.tgz │ │ │ ├── dynatrace-operator-0.10.2.tgz │ │ │ ├── dynatrace-operator-0.10.3.tgz │ │ │ ├── dynatrace-operator-0.10.4.tgz │ │ │ ├── dynatrace-operator-0.11.0.tgz │ │ │ ├── dynatrace-operator-0.11.1.tgz │ │ │ ├── dynatrace-operator-0.11.2.tgz │ │ │ ├── dynatrace-operator-0.11.3.tgz │ │ │ ├── dynatrace-operator-0.12.0.tgz │ │ │ ├── dynatrace-operator-0.12.1.tgz │ │ │ ├── dynatrace-operator-0.13.0.tgz │ │ │ ├── dynatrace-operator-0.13.1.tgz │ │ │ ├── dynatrace-operator-0.4.0.tgz │ │ │ ├── dynatrace-operator-0.4.1.tgz │ │ │ ├── dynatrace-operator-0.4.2.tgz │ │ │ ├── dynatrace-operator-0.5.0.tgz │ │ │ ├── dynatrace-operator-0.8.0.tgz │ │ │ ├── dynatrace-operator-0.8.1.tgz │ │ │ ├── dynatrace-operator-0.8.2.tgz │ │ │ ├── dynatrace-operator-0.9.0.tgz │ │ │ ├── dynatrace-operator-0.9.1.tgz │ │ │ ├── dynatrace-operator-0.9.2.tgz │ │ │ └── artifacthub-repo.yml │ ├── Dockerfile │ └── README.md ├── deploy │ ├── kubernetes │ │ └── kustomization.yaml │ └── openshift │ │ └── kustomization.yaml └── olm │ ├── kubernetes │ └── kustomization.yaml │ └── openshift │ └── kustomization.yaml ├── assets ├── samples │ ├── dynakube │ │ └── kustomization.yaml │ └── edgeconnect │ │ └── edgeconnect.yaml ├── calico │ ├── agent-policy.yaml │ └── agent-policy-external-only.yaml └── docker │ ├── codeModulesARM.Dockerfile │ └── codeModulesAMD.Dockerfile ├── test ├── testdata │ ├── sample-app │ │ ├── serviceaccount.yaml │ │ ├── binding.yaml │ │ └── clusterrole.yaml │ ├── custom-cas │ │ ├── agcrtkey.p12 │ │ └── ag.ext │ ├── network │ │ ├── ocp-istio-cni.yaml │ │ ├── proxy-ssl-namespace.yaml │ │ ├── dynatrace-denial.yaml │ │ ├── csi-denial.yaml │ │ └── proxy-scc.yaml │ ├── secrets-samples │ │ ├── edgeconnect-tenant.yaml │ │ ├── README.md │ │ ├── single-tenant.yaml │ │ └── multi-tenant.yaml │ └── edgeconnect │ │ └── custom-service-account.yaml ├── helpers │ ├── shell │ │ └── shell_test.go │ ├── kubeobjects │ │ ├── environment │ │ │ └── environment.go │ │ ├── pod │ │ │ └── list.go │ │ ├── service │ │ │ └── list.go │ │ ├── event │ │ │ └── list.go │ │ ├── manifests │ │ │ └── decode.go │ │ ├── statefulset │ │ │ └── get.go │ │ └── job │ │ │ └── wait.go │ ├── components │ │ ├── webhook │ │ │ └── deployment.go │ │ └── operator │ │ │ └── deployment.go │ └── tenant │ │ └── secrets_test.go └── project │ └── project.go ├── cmd ├── metadata │ ├── config.go │ └── writer.go ├── webhook │ └── certificates │ │ └── config.go ├── supportarchive │ ├── collector.go │ ├── resource_query_test.go │ ├── logger_test.go │ └── config.go ├── troubleshoot │ ├── crd.go │ ├── oneagentapm.go │ ├── namespace.go │ └── logger_test.go └── operator │ ├── manager_test.go │ └── config.go ├── .markdownlint.json ├── .editorconfig ├── SECURITY.md └── .snyk /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @Dynatrace/kubernetes-operator 2 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/image/unpack_test.go: -------------------------------------------------------------------------------- 1 | package image 2 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | paths-ignore: 2 | - 'assets/docker' 3 | -------------------------------------------------------------------------------- /hack/build/bin/entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | exec "${OPERATOR}" "$@" 4 | -------------------------------------------------------------------------------- /config/manifests/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - ../../assets/samples/dynakube 3 | -------------------------------------------------------------------------------- /hack/requirements.txt: -------------------------------------------------------------------------------- 1 | argparse==1.4.0 2 | pyyaml==6.0.3 3 | json5==0.12.1 4 | ruamel.yaml==0.18.17 5 | -------------------------------------------------------------------------------- /assets/samples/dynakube/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: [] 2 | # +kubebuilder:scaffold:manifestskustomizesamples 3 | -------------------------------------------------------------------------------- /config/crd/bases/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - dynatrace.com_dynakubes.yaml 3 | - dynatrace.com_edgeconnects.yaml 4 | 5 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/tls/conditions.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | const conditionType string = "ExtensionsTLSSecret" 4 | -------------------------------------------------------------------------------- /test/testdata/sample-app/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: e2e-samples 5 | -------------------------------------------------------------------------------- /config/helm/chart/default/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/chart/default/logo.png -------------------------------------------------------------------------------- /pkg/consts/host_availability.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const HostAvailabilityDetectionEnvVar = "DT_HOST_AVAILABILITY_DETECTION" 4 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/dtpullsecret/conditions.go: -------------------------------------------------------------------------------- 1 | package dtpullsecret 2 | 3 | const PullSecretConditionType = "PullSecret" 4 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/kspm/token/conditions.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | const ( 4 | kspmConditionType = "KSPMTokenSecret" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/tls/conditions.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | const ( 4 | conditionType = "TLSSecret" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/k8sentity/conditions.go: -------------------------------------------------------------------------------- 1 | package k8sentity 2 | 3 | const ( 4 | meIDConditionType = "MonitoredEntity" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/service/conditions.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | const ( 4 | serviceConditionType = "OTELCService" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/statefulset/conditions.go: -------------------------------------------------------------------------------- 1 | package statefulset 2 | 3 | const conditionType string = "OtelStatefulSet" 4 | -------------------------------------------------------------------------------- /test/testdata/custom-cas/agcrtkey.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/test/testdata/custom-cas/agcrtkey.p12 -------------------------------------------------------------------------------- /hack/make/kind.mk: -------------------------------------------------------------------------------- 1 | ## Setup a local Kubernetes cluster using KinD 2 | kind/setup: prerequisites/yq 3 | ./hack/kind/setup.sh $(K8S_VERSION) 4 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/metadata/rules/conditions.go: -------------------------------------------------------------------------------- 1 | package rules 2 | 3 | const ( 4 | conditionType = "MetadataEnrichmentRules" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/api/v1alpha2/edgeconnect/config.go: -------------------------------------------------------------------------------- 1 | package edgeconnect 2 | 3 | import "time" 4 | 5 | const DefaultMinRequestThreshold = 15 * time.Minute 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/kspm/daemonset/conditions.go: -------------------------------------------------------------------------------- 1 | package daemonset 2 | 3 | const ( 4 | conditionType = "NodeConfigCollectorDaemonSet" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/logmonitoring/daemonset/conditions.go: -------------------------------------------------------------------------------- 1 | package daemonset 2 | 3 | const ( 4 | ConditionType = "LogMonitoringDaemonSet" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/configuration/conditions.go: -------------------------------------------------------------------------------- 1 | package configuration 2 | 3 | const conditionType string = "OTELCConfigurationConfigMap" 4 | -------------------------------------------------------------------------------- /pkg/util/builder/mocks/data.go: -------------------------------------------------------------------------------- 1 | package mocks 2 | 3 | import "github.com/stretchr/testify/mock" 4 | 5 | type DataMock struct { 6 | mock.Mock 7 | } 8 | -------------------------------------------------------------------------------- /test/testdata/network/ocp-istio-cni.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "k8s.cni.cncf.io/v1" 2 | kind: NetworkAttachmentDefinition 3 | metadata: 4 | name: istio-cni 5 | -------------------------------------------------------------------------------- /pkg/arch/amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 2 | 3 | package arch 4 | 5 | const Arch = ArchX86 6 | const ImageArch = AMDImage 7 | const Flavor = FlavorMultidistro 8 | -------------------------------------------------------------------------------- /pkg/arch/arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 2 | 3 | package arch 4 | 5 | const Arch = ArchARM 6 | const ImageArch = ARMImage 7 | const Flavor = FlavorMultidistro 8 | -------------------------------------------------------------------------------- /pkg/arch/s390x.go: -------------------------------------------------------------------------------- 1 | //go:build s390x 2 | 3 | package arch 4 | 5 | const Arch = ArchS390 6 | const ImageArch = S390Image 7 | const Flavor = FlavorDefault 8 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/endpoint/conditions.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | const ( 4 | configMapConditionType = "OtelpApiEndpointConfigMap" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/arch/ppc64le.go: -------------------------------------------------------------------------------- 1 | //go:build ppc64le 2 | 3 | package arch 4 | 5 | const Arch = ArchPPCLE 6 | const Flavor = FlavorDefault 7 | const ImageArch = PPCLEImage 8 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/logmonitoring/configsecret/conditions.go: -------------------------------------------------------------------------------- 1 | package configsecret 2 | 3 | const ( 4 | LmcConditionType = "LogMonitoringConfig" 5 | ) 6 | -------------------------------------------------------------------------------- /pkg/controllers/reconciler.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import "context" 4 | 5 | type Reconciler interface { 6 | Reconcile(ctx context.Context) error 7 | } 8 | -------------------------------------------------------------------------------- /pkg/util/kubesystem/execution_env.go: -------------------------------------------------------------------------------- 1 | package kubesystem 2 | 3 | import "os" 4 | 5 | func IsRunLocally() bool { 6 | return os.Getenv("RUN_LOCAL") == "true" 7 | } 8 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/mutator/otlp/exporter/config.go: -------------------------------------------------------------------------------- 1 | package exporter 2 | 3 | const ( 4 | CouldNotGetIngestEndpointReason = "IngestEndpointUnavailable" 5 | ) 6 | -------------------------------------------------------------------------------- /cmd/metadata/config.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var log = logd.Get().WithName("metadata-generator") 6 | -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.10.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.10.0.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.10.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.10.1.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.10.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.10.2.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.10.3.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.10.3.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.10.4.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.10.4.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.11.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.11.0.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.11.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.11.1.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.11.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.11.2.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.11.3.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.11.3.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.12.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.12.0.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.12.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.12.1.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.13.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.13.0.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.13.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.13.1.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.4.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.4.0.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.4.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.4.1.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.4.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.4.2.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.5.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.5.0.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.8.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.8.0.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.8.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.8.1.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.8.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.8.2.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.9.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.9.0.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.9.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.9.1.tgz -------------------------------------------------------------------------------- /config/helm/repos/stable/dynatrace-operator-0.9.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dynatrace/dynatrace-operator/HEAD/config/helm/repos/stable/dynatrace-operator-0.9.2.tgz -------------------------------------------------------------------------------- /hack/make/tests/olm.mk: -------------------------------------------------------------------------------- 1 | ## Installs a custom catalog source and adds a Dynatrace Operator subscription to test OLM installs 2 | test/olm: 3 | ./hack/setup_olm_catalog.sh 4 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/eec/conditions.go: -------------------------------------------------------------------------------- 1 | package eec 2 | 3 | const extensionControllerStatefulSetConditionType string = "ExtensionControllerStatefulSet" 4 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/statefulset/conditions.go: -------------------------------------------------------------------------------- 1 | package statefulset 2 | 3 | const ActiveGateStatefulSetConditionType string = "ActiveGateStatefulSet" 4 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/connectioninfo/activegate/conditions.go: -------------------------------------------------------------------------------- 1 | package activegate 2 | 3 | const activeGateConnectionInfoConditionType string = "ActiveGateConnectionInfo" 4 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/conversion.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | // Hub tags this version as the 'source' of the conversion for controller runtime. 4 | func (*DynaKube) Hub() {} 5 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/customproperties/conditions.go: -------------------------------------------------------------------------------- 1 | package customproperties 2 | 3 | const customPropertiesConditionType string = "CustomPropertiesSecret" 4 | -------------------------------------------------------------------------------- /config/deploy/kubernetes/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - kubernetes.yaml # only used in OLM bundle creation 5 | -------------------------------------------------------------------------------- /config/deploy/openshift/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - openshift.yaml # only used in OLM bundle creation 5 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/iface.go: -------------------------------------------------------------------------------- 1 | package activegate 2 | 3 | import "context" 4 | 5 | type CapabilityReconciler interface { 6 | Reconcile(ctx context.Context) error 7 | } 8 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/conditions.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | const ( 4 | secretConditionType = "ExtensionsSecret" 5 | serviceConditionType = "ExtensionsService" 6 | ) 7 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/token/config.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var ( 6 | log = logd.Get().WithName("tokens") 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/api/v1alpha2/edgeconnect/conversion.go: -------------------------------------------------------------------------------- 1 | package edgeconnect 2 | 3 | // Hub tags this version as the 'source' of the conversion for controller runtime. 4 | func (*EdgeConnect) Hub() {} 5 | -------------------------------------------------------------------------------- /config/olm/kubernetes/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../deploy/kubernetes 5 | - ../../../assets/samples/dynakube 6 | -------------------------------------------------------------------------------- /config/olm/openshift/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../deploy/openshift 5 | - ../../../assets/samples/dynakube 6 | -------------------------------------------------------------------------------- /pkg/consts/otlp.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | OTLPExporterSecretName = "dynatrace-otlp-exporter-config" 5 | OTLPExporterCertsSecretName = "dynatrace-otlp-exporter-certs" 6 | ) 7 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/proxy/config.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var log = logd.Get().WithName("dynakube-proxy") 8 | -------------------------------------------------------------------------------- /pkg/otlp/exporterconfig/conditions.go: -------------------------------------------------------------------------------- 1 | package exporterconfig 2 | 3 | const ( 4 | ConfigConditionType = "OTLPExporterConfigSecret" 5 | CertsConditionType = "OTLPExporterCertsConfig" 6 | ) 7 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/databases/conditions.go: -------------------------------------------------------------------------------- 1 | package databases 2 | 3 | // DynaKube condition that is managed by the reconciler. 4 | const conditionType = "DatabaseDatasourcesAvailable" 5 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/kspm/token/config.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var ( 6 | log = logd.Get().WithName("kspm-token-secret") 7 | ) 8 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD013": false, 3 | "MD024": false, 4 | "MD029": false, 5 | "MD033": false, 6 | "MD034": false, 7 | "MD037": false, 8 | "MD041": false 9 | } 10 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/metadataenrichment/status.go: -------------------------------------------------------------------------------- 1 | package metadataenrichment 2 | 3 | // +kubebuilder:object:generate=true 4 | 5 | type Status struct { 6 | Rules []Rule `json:"rules,omitempty"` 7 | } 8 | -------------------------------------------------------------------------------- /pkg/clients/dynatrace/config.go: -------------------------------------------------------------------------------- 1 | package dynatrace 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("dtclient") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/databases/config.go: -------------------------------------------------------------------------------- 1 | package databases 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var log = logd.Get().WithName("extension-databases") 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/kspm/config.go: -------------------------------------------------------------------------------- 1 | package kspm 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("kspm") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/service/config.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var ( 6 | log = logd.Get().WithName("otelc-service") 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/installer.go: -------------------------------------------------------------------------------- 1 | package installer 2 | 3 | import "context" 4 | 5 | type Installer interface { 6 | InstallAgent(ctx context.Context, targetDir string) (bool, error) 7 | } 8 | -------------------------------------------------------------------------------- /test/testdata/network/proxy-ssl-namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: proxy 5 | annotations: 6 | dynatrace.com/inject: "false" 7 | labels: 8 | app: squid 9 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/config.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("dynakube") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/injection/namespace/bootstrapperconfig/conditions.go: -------------------------------------------------------------------------------- 1 | package bootstrapperconfig 2 | 3 | const ( 4 | ConfigConditionType = "BootstrapperConfig" 5 | CertsConditionType = "BootstrapperCertsConfig" 6 | ) 7 | -------------------------------------------------------------------------------- /pkg/controllers/csi/metadata/config.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("csi-metadata") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/config.go: -------------------------------------------------------------------------------- 1 | package otelc 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("otel-collector") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/configuration/config.go: -------------------------------------------------------------------------------- 1 | package configuration 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var ( 6 | log = logd.Get().WithName("otelc-config") 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/controllers/edgeconnect/config.go: -------------------------------------------------------------------------------- 1 | package edgeconnect 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("edgeconnect") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/config.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("extension") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/eec/config.go: -------------------------------------------------------------------------------- 1 | package eec 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("extension-eec") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/tls/config.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("extension-tls") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/job/config.go: -------------------------------------------------------------------------------- 1 | package job 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("oneagent-job") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/oci/dockerkeychain/config.go: -------------------------------------------------------------------------------- 1 | package dockerkeychain 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("docker-keychain") 9 | ) 10 | -------------------------------------------------------------------------------- /cmd/webhook/certificates/config.go: -------------------------------------------------------------------------------- 1 | package certificates 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("certificate-watcher") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/csi/provisioner/cleanup/config.go: -------------------------------------------------------------------------------- 1 | package cleanup 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("csi-cleanup") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/tls/config.go: -------------------------------------------------------------------------------- 1 | package tls 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var ( 6 | log = logd.Get().WithName("dynakube-activegate-tls-secret") 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/oneagent/config.go: -------------------------------------------------------------------------------- 1 | package oneagent 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("dynakube-oneagent") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/version/config.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("dynakube-version") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/edgeconnect/secret/config.go: -------------------------------------------------------------------------------- 1 | package secret 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("edgeconnect-secret") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/injection/namespace/bootstrapperconfig/config.go: -------------------------------------------------------------------------------- 1 | package bootstrapperconfig 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var ( 6 | log = logd.Get().WithName("bootstrapper-config") 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/namespace/config.go: -------------------------------------------------------------------------------- 1 | package namespace 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("namespace-mutation") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/certificates/config.go: -------------------------------------------------------------------------------- 1 | package certificates 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("webhook-certificates") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/csi/provisioner/config.go: -------------------------------------------------------------------------------- 1 | package csiprovisioner 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("csi-provisioner") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/config.go: -------------------------------------------------------------------------------- 1 | package activegate 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("dynakube-activegate") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/injection/config.go: -------------------------------------------------------------------------------- 1 | package injection 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("dynakube-injection") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/k8sentity/config.go: -------------------------------------------------------------------------------- 1 | package k8sentity 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("monitored-entities") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/kspm/daemonset/config.go: -------------------------------------------------------------------------------- 1 | package daemonset 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("kspm-daemonset") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/endpoint/config.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var ( 6 | log = logd.Get().WithName("telemetry-ingest-api-credentials-secret") 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/controllers/edgeconnect/version/config.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("edgeconnect-version") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/util/kubernetes/objects/k8sstatefulset/consts.go: -------------------------------------------------------------------------------- 1 | package k8sstatefulset 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/api" 4 | 5 | const ( 6 | AnnotationPVCHash = api.InternalFlagPrefix + "pvc-hash" 7 | ) 8 | -------------------------------------------------------------------------------- /pkg/clients/utils/http.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "net/http" 4 | 5 | func CloseBodyAfterRequest(response *http.Response) { 6 | if response != nil && response.Body != nil { 7 | _ = response.Body.Close() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/dtpullsecret/config.go: -------------------------------------------------------------------------------- 1 | package dtpullsecret 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("dynakube-pullsecret") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/metadata/rules/config.go: -------------------------------------------------------------------------------- 1 | package rules 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("metadata-enrichment-rules") 9 | ) 10 | -------------------------------------------------------------------------------- /test/testdata/secrets-samples/edgeconnect-tenant.yaml: -------------------------------------------------------------------------------- 1 | name: name-of-your-edge-connect 2 | tenantUid: abc12345 3 | apiServer: abc12345.dev.apps.dynatracelabs.com 4 | oAuthClientId: test 5 | oAuthClientSecret: test 6 | resource: test 7 | -------------------------------------------------------------------------------- /pkg/controllers/csi/driver/volumes/host/config.go: -------------------------------------------------------------------------------- 1 | package host 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const Mode = "host" 8 | 9 | var log = logd.Get().WithName("csi-hostvolume") 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/capability/config.go: -------------------------------------------------------------------------------- 1 | package capability 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var log = logd.Get().WithName("dynakube-activegate-capability") 8 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/consts/consts.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | TokenSecretKey = "eec.token" 5 | TokenSecretValuePrefix = "EEC dt0x01" 6 | 7 | ExtensionControllerSuffix = "-extension-controller" 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/oneagent/daemonset/config.go: -------------------------------------------------------------------------------- 1 | package daemonset 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("oneagent-daemonset") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/statefulset/config.go: -------------------------------------------------------------------------------- 1 | package statefulset 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("otelc-statefulset") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/edgeconnect/deployment/config.go: -------------------------------------------------------------------------------- 1 | package deployment 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("edgeconnect-deployment") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/edgeconnect/version/iface.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import "context" 4 | 5 | type versionStatusUpdater interface { 6 | Name() string 7 | RequiresReconcile() bool 8 | Update(ctx context.Context) error 9 | } 10 | -------------------------------------------------------------------------------- /test/testdata/secrets-samples/README.md: -------------------------------------------------------------------------------- 1 | # Secrets 2 | 3 | The tests need connection info to tenants. 4 | The secrets need to be placed inside a yaml under `/test/testdata/secrets/`. 5 | Samples of the files can be found in this directory. 6 | -------------------------------------------------------------------------------- /test/testdata/secrets-samples/single-tenant.yaml: -------------------------------------------------------------------------------- 1 | tenantUid: abc1234 2 | apiUrl: https://abc1234.dev.dynatracelabs.com/api 3 | apiToken: 4 | apiTokenNoSettings: 5 | dataIngestToken: 6 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/apimonitoring/config.go: -------------------------------------------------------------------------------- 1 | package apimonitoring 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("automatic-api-monitoring") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/otelcgen/testdata/extensions_only.yaml: -------------------------------------------------------------------------------- 1 | connectors: {} 2 | exporters: {} 3 | extensions: 4 | health_check: 5 | endpoint: test:13133 6 | processors: {} 7 | receivers: {} 8 | service: 9 | extensions: [] 10 | pipelines: {} 11 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/logmonitoring/daemonset/config.go: -------------------------------------------------------------------------------- 1 | package daemonset 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("logmonitoring-daemonset") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/common/consts.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | const ( 4 | AgentConfDirPath = "agent/conf" 5 | RuxitConfFileName = "ruxitagentproc.conf" 6 | MkDirFileMode = 0755 7 | ReadWriteAllFileMode = 0666 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/consts/agent_injection.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | BootstrapperInitSecretName = "dynatrace-bootstrapper-config" 5 | BootstrapperInitCertsSecretName = "dynatrace-bootstrapper-certs" 6 | 7 | AgentInitBinDirMount = "/mnt/bin" 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/connectioninfo/activegate/config.go: -------------------------------------------------------------------------------- 1 | package activegate 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("activegate-connectioninfo") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/connectioninfo/oneagent/config.go: -------------------------------------------------------------------------------- 1 | package oaconnectioninfo 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("oneagent-connectioninfo") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/logmonitoring/logmonsettings/config.go: -------------------------------------------------------------------------------- 1 | package logmonsettings 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("logmonitoring-settings") 9 | ) 10 | -------------------------------------------------------------------------------- /test/testdata/network/dynatrace-denial.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.istio.io/v1beta1 2 | kind: Sidecar 3 | metadata: 4 | name: deny-all 5 | namespace: dynatrace 6 | spec: 7 | outboundTrafficPolicy: 8 | mode: REGISTRY_ONLY 9 | 10 | 11 | -------------------------------------------------------------------------------- /hack/build/ci/sanitize-branch-name.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | readonly BRANCH_NAME=${1} 4 | 5 | if [ -z "${BRANCH_NAME}" ]; then 6 | echo "Usage: $0 " >&2 7 | exit 1 8 | fi 9 | 10 | echo "${BRANCH_NAME//[^a-zA-Z0-9_.-]/-}" 11 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/authtoken/config.go: -------------------------------------------------------------------------------- 1 | package authtoken 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("dynakube-activegate-authtoken") 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/handler/interface.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import dtwebhook "github.com/Dynatrace/dynatrace-operator/pkg/webhook/mutation/pod/mutator" 4 | 5 | type Handler interface { 6 | Handle(mutationRequest *dtwebhook.MutationRequest) error 7 | } 8 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/customproperties/config.go: -------------------------------------------------------------------------------- 1 | package customproperties 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("activegate-customproperties") 9 | ) 10 | -------------------------------------------------------------------------------- /hack/helm/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "Unit-testing helm chart" 3 | if ! helm unittest -f './tests/*/*/*/*.yaml' -f './tests/*/*/*.yaml' -f './tests/*/*.yaml' -f './tests/*.yaml' ./config/helm/chart/default; then 4 | echo "some tests failed" 5 | exit 10 6 | fi 7 | -------------------------------------------------------------------------------- /pkg/util/functional/map.go: -------------------------------------------------------------------------------- 1 | package functional 2 | 3 | func Map[In any, Out any](arr []In, transformFn func(it In) Out) []Out { 4 | ret := make([]Out, len(arr)) 5 | 6 | for i, it := range arr { 7 | ret[i] = transformFn(it) 8 | } 9 | 10 | return ret 11 | } 12 | -------------------------------------------------------------------------------- /pkg/api/validation/edgeconnect/config.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const ( 8 | testServiceAccountName = "test" 9 | ) 10 | 11 | var log = logd.Get().WithName("edgeconnect-validation") 12 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/url/config.go: -------------------------------------------------------------------------------- 1 | package url 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("oneagent-url") 9 | ) 10 | 11 | const ( 12 | VersionLatest = "latest" 13 | ) 14 | -------------------------------------------------------------------------------- /test/testdata/secrets-samples/multi-tenant.yaml: -------------------------------------------------------------------------------- 1 | tenants: 2 | - tenantUid: abc1234 3 | apiUrl: https://abc1234.dev.dynatracelabs.com/api 4 | apiToken: 5 | - tenantUid: def5678 6 | apiUrl: https://def5678.dev.dynatracelabs.com/api 7 | apiToken: -------------------------------------------------------------------------------- /pkg/controllers/nodes/config.go: -------------------------------------------------------------------------------- 1 | package nodes 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("nodes") 9 | unschedulableTaints = []string{"ToBeDeletedByClusterAutoscaler"} 10 | ) 11 | -------------------------------------------------------------------------------- /pkg/util/projectpath/projectpath.go: -------------------------------------------------------------------------------- 1 | package projectpath 2 | 3 | import ( 4 | "path/filepath" 5 | "runtime" 6 | ) 7 | 8 | var ( 9 | _, b, _, _ = runtime.Caller(0) 10 | 11 | // Root folder of this project 12 | Root = filepath.Join(filepath.Dir(b), "..", "..", "..") 13 | ) 14 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/oneagent/error_handler.go: -------------------------------------------------------------------------------- 1 | package oneagent 2 | 3 | import ( 4 | "sigs.k8s.io/controller-runtime/pkg/client" 5 | ) 6 | 7 | func handlePodListError(err error, listOps []client.ListOption) { 8 | log.Error(err, "failed to list pods", "listops", listOps) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/proxy/volumes.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | ) 6 | 7 | func BuildVolumeMount() corev1.VolumeMount { 8 | return corev1.VolumeMount{ 9 | Name: SecretVolumeName, 10 | MountPath: SecretMountPath, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pkg/util/functional/filter.go: -------------------------------------------------------------------------------- 1 | package functional 2 | 3 | func Filter[T any](arr []T, predicate func(val T) bool) []T { 4 | ret := make([]T, 0) 5 | 6 | for _, val := range arr { 7 | if predicate(val) { 8 | ret = append(ret, val) 9 | } 10 | } 11 | 12 | return ret 13 | } 14 | -------------------------------------------------------------------------------- /test/testdata/custom-cas/ag.ext: -------------------------------------------------------------------------------- 1 | authorityKeyIdentifier=keyid,issuer 2 | basicConstraints=CA:FALSE 3 | subjectAltName = @alt_names 4 | [alt_names] 5 | DNS.1 = dynakube-activegate.dynatrace 6 | DNS.2 = dynakube-activegate.dynatrace.svc 7 | DNS.3 = dynakube-activegate.dynatrace.svc.cluster.local 8 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - bases 3 | #+kubebuilder:scaffold:crdkustomizeresource 4 | 5 | apiVersion: kustomize.config.k8s.io/v1beta1 6 | kind: Kustomization 7 | patches: 8 | - path: patches/webhook_in_dynakubes.yaml 9 | - path: patches/webhook_in_edgeconnects.yaml 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.go] 12 | indent_style = tab 13 | 14 | [*.yaml] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /pkg/api/consts.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | const ( 4 | LatestTag = "latest" 5 | RawTag = "raw" 6 | InternalFlagPrefix = "internal.operator.dynatrace.com/" 7 | AnnotationExtensionsSecretHash = InternalFlagPrefix + "extensions-secret-hash" 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/api/status/phase.go: -------------------------------------------------------------------------------- 1 | // +kubebuilder:object:generate=true 2 | // +k8s:openapi-gen=true 3 | package status 4 | 5 | type DeploymentPhase string 6 | 7 | const ( 8 | Running DeploymentPhase = "Running" 9 | Deploying DeploymentPhase = "Deploying" 10 | Error DeploymentPhase = "Error" 11 | ) 12 | -------------------------------------------------------------------------------- /hack/make/tests/helm.mk: -------------------------------------------------------------------------------- 1 | ## Unit tests the Helm charts 2 | test/helm/unit: prerequisites/helm-unittest 3 | ./hack/helm/test.sh 4 | 5 | ## Lints the Helm charts 6 | test/helm/lint: 7 | ./hack/helm/lint.sh 8 | 9 | ## Lints and then unit tests the Helm charts 10 | test/helm: test/helm/lint test/helm/unit 11 | -------------------------------------------------------------------------------- /test/testdata/sample-app/binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: e2e-samples 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: e2e-samples 9 | subjects: 10 | - kind: ServiceAccount 11 | name: e2e-samples 12 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Security related information can be found in the official docs: 4 | 5 | - Network-traffic: https://docs.dynatrace.com/docs/ingest-from/setup-on-k8s/reference/security 6 | - Permissions/Security-Benchmarks: https://docs.dynatrace.com/docs/ingest-from/setup-on-k8s/reference/network 7 | -------------------------------------------------------------------------------- /config/helm/repos/stable/artifacthub-repo.yml: -------------------------------------------------------------------------------- 1 | repositoryID: b0a4eac3-5980-4825-a4d7-77f116e2e6ab 2 | owners: 3 | - name: 0sewa0 4 | email: marcell.sevcsik@dynatrace.com 5 | - name: chrismuellner 6 | email: christoph.muellner@dynatrace.com 7 | - name: luhi-DT 8 | email: lukas.hinterreiter@dynatrace.com 9 | -------------------------------------------------------------------------------- /pkg/consts/tls.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | 5 | // TLSKeyDataName is the key used to store a TLS private key in the secret's data field. 6 | TLSKeyDataName = "tls.key" 7 | 8 | // TLSCrtDataName is the key used to store a TLS certificate in the secret's data field. 9 | TLSCrtDataName = "tls.crt" 10 | ) 11 | -------------------------------------------------------------------------------- /cmd/supportarchive/collector.go: -------------------------------------------------------------------------------- 1 | package supportarchive 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | type collector interface { 8 | Name() string 9 | Do() error 10 | } 11 | 12 | type collectorCommon struct { 13 | supportArchive archiver 14 | log logd.Logger 15 | } 16 | -------------------------------------------------------------------------------- /pkg/controllers/csi/driver/volumes/publisher.go: -------------------------------------------------------------------------------- 1 | package csivolumes 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/container-storage-interface/spec/lib/go/csi" 7 | ) 8 | 9 | type Publisher interface { 10 | PublishVolume(ctx context.Context, volumeCfg *VolumeConfig) (*csi.NodePublishVolumeResponse, error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/logmonitoring/configsecret/config.go: -------------------------------------------------------------------------------- 1 | package configsecret 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const ( 8 | DeploymentConfigFilename = "deployment.conf" 9 | ) 10 | 11 | var ( 12 | log = logd.Get().WithName("logmonitoring-config-secret") 13 | ) 14 | -------------------------------------------------------------------------------- /test/testdata/sample-app/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: e2e-samples 5 | rules: 6 | - apiGroups: 7 | - security.openshift.io 8 | resourceNames: 9 | - privileged 10 | resources: 11 | - securitycontextconstraints 12 | verbs: 13 | - use 14 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/statefulset/config.go: -------------------------------------------------------------------------------- 1 | package statefulset 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const ( 8 | InternalProxySecretVolumeName = "internal-proxy-secret-volume" 9 | ) 10 | 11 | var ( 12 | log = logd.Get().WithName("activegate-statefulset") 13 | ) 14 | -------------------------------------------------------------------------------- /hack/gcr/deployer-image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | export REGISTRY=gcr.io/dynatrace-marketplace-dev 6 | export APP_NAME=dynatrace-operator 7 | TAG="${1:-""}" 8 | 9 | if docker build --tag "$REGISTRY/$APP_NAME/deployer${TAG}" -f config/helm/Dockerfile config/helm; then 10 | docker push "$REGISTRY/$APP_NAME/deployer${TAG}" 11 | fi 12 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/proxy/consts.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | const ( 4 | hostField = "host" 5 | portField = "port" 6 | usernameField = "username" 7 | passwordField = "password" 8 | schemeField = "scheme" 9 | 10 | SecretMountPath = "/var/lib/dynatrace/secrets/internal-proxy" 11 | SecretVolumeName = "internal-proxy-secret-volume" 12 | ) 13 | -------------------------------------------------------------------------------- /hack/build/create_go_build_tags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ]; then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | needs_e2e_tag=$1 9 | 10 | go_build_tags=() 11 | 12 | if "${needs_e2e_tag}"; then 13 | # Used for enabling e2e testing code 14 | go_build_tags+=("e2e") 15 | fi 16 | 17 | printf "%s," "${go_build_tags[@]}" 18 | -------------------------------------------------------------------------------- /hack/do_env_variables_exist.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # check if parameters are set 4 | if [ -z "$1" ] 5 | then 6 | echo "Usage: $0 " 7 | exit 1 8 | fi 9 | 10 | # make sure all fields are set 11 | for field in $1; do 12 | if [ -z "${!field}" ]; then 13 | echo "Error: $field is not set" 14 | exit 1 15 | fi 16 | done 17 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/logmonitoring/ingestrulematchers.go: -------------------------------------------------------------------------------- 1 | package logmonitoring 2 | 3 | // +kubebuilder:object:generate=true 4 | 5 | type IngestRuleMatchers struct { 6 | // +kubebuilder:validation:Optional 7 | Attribute string `json:"attribute,omitempty"` 8 | 9 | // +kubebuilder:validation:Optional 10 | Values []string `json:"values,omitempty"` 11 | } 12 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/logmonitoring/ingestrulematchers.go: -------------------------------------------------------------------------------- 1 | package logmonitoring 2 | 3 | // +kubebuilder:object:generate=true 4 | 5 | type IngestRuleMatchers struct { 6 | // +kubebuilder:validation:Optional 7 | Attribute string `json:"attribute,omitempty"` 8 | 9 | // +kubebuilder:validation:Optional 10 | Values []string `json:"values,omitempty"` 11 | } 12 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/logmonitoring/ingestrulematchers.go: -------------------------------------------------------------------------------- 1 | package logmonitoring 2 | 3 | // +kubebuilder:object:generate=true 4 | 5 | type IngestRuleMatchers struct { 6 | // +kubebuilder:validation:Optional 7 | Attribute string `json:"attribute,omitempty"` 8 | 9 | // +kubebuilder:validation:Optional 10 | Values []string `json:"values,omitempty"` 11 | } 12 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/logmonitoring/ingestrulematchers.go: -------------------------------------------------------------------------------- 1 | package logmonitoring 2 | 3 | // +kubebuilder:object:generate=true 4 | 5 | type IngestRuleMatchers struct { 6 | // +kubebuilder:validation:Optional 7 | Attribute string `json:"attribute,omitempty"` 8 | 9 | // +kubebuilder:validation:Optional 10 | Values []string `json:"values,omitempty"` 11 | } 12 | -------------------------------------------------------------------------------- /pkg/otelcgen/testdata/exporters_only.yaml: -------------------------------------------------------------------------------- 1 | connectors: {} 2 | exporters: 3 | otlphttp: 4 | endpoint: "test" 5 | tls: 6 | ca_file: "/run/opensignals/cacerts/certs" 7 | 8 | headers: 9 | Authorization: "Api-Token test-token" 10 | extensions: {} 11 | processors: {} 12 | receivers: {} 13 | service: 14 | extensions: [] 15 | pipelines: {} 16 | -------------------------------------------------------------------------------- /hack/build/ci/third-party-licenses.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #renovate depName=github.com/google/go-licenses 3 | GOLANG_LICENSES_VERSION=v2.0.1 4 | 5 | # get licenses if no cache exists 6 | if ! [ -d ./third_party_licenses ]; then 7 | go install github.com/google/go-licenses/v2@"$GOLANG_LICENSES_VERSION" && go-licenses save ./... --save_path third_party_licenses --force 8 | fi 9 | -------------------------------------------------------------------------------- /pkg/api/validation/dynakube/preview.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | const ( 4 | featurePreviewWarningMessage = `%s feature is in PREVIEW.` //nolint:unused 5 | basePreviewWarning = "PREVIEW features are NOT production ready and you may run into bugs." //nolint:unused 6 | ) 7 | 8 | // Logics related to preview warnings go here. 9 | -------------------------------------------------------------------------------- /pkg/otelcgen/consts.go: -------------------------------------------------------------------------------- 1 | package otelcgen 2 | 3 | const ( 4 | OtlpGrpcPort = 4317 5 | OtlpHTTPPort = 4318 6 | 7 | JaegerGrpcPort = 14250 8 | JaegerThriftBinaryPort = 6832 9 | JaegerThriftCompactPort = 6831 10 | JaegerThriftHTTPPort = 14268 11 | 12 | ZipkinPort = 9411 13 | 14 | StatsdPort = 8125 15 | 16 | ExtensionsHealthCheckPort = 13133 17 | ) 18 | -------------------------------------------------------------------------------- /pkg/otelcgen/testdata/receivers_zipkin_only.yaml: -------------------------------------------------------------------------------- 1 | connectors: {} 2 | exporters: {} 3 | extensions: {} 4 | processors: {} 5 | receivers: 6 | zipkin: 7 | endpoint: test:9411 8 | tls: 9 | cert_file: /run/opensignals/tls/tls.crt 10 | key_file: /run/opensignals/tls/tls.key 11 | service: 12 | extensions: [] 13 | pipelines: {} 14 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/image/config.go: -------------------------------------------------------------------------------- 1 | package image 2 | 3 | import ( 4 | "path/filepath" 5 | 6 | dtcsi "github.com/Dynatrace/dynatrace-operator/pkg/controllers/csi" 7 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 8 | ) 9 | 10 | var ( 11 | CacheDir = filepath.Join(dtcsi.DataPath, "cache") 12 | log = logd.Get().WithName("oneagent-image") 13 | ) 14 | -------------------------------------------------------------------------------- /test/testdata/network/csi-denial.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.istio.io/v1beta1 2 | kind: Sidecar 3 | metadata: 4 | name: deny-csi 5 | namespace: dynatrace 6 | spec: 7 | workloadSelector: 8 | labels: 9 | app.kubernetes.io/name: dynatrace-operator 10 | app.kubernetes.io/component: csi-driver 11 | outboundTrafficPolicy: 12 | mode: REGISTRY_ONLY 13 | 14 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/symlink/config.go: -------------------------------------------------------------------------------- 1 | package symlink 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const ( 8 | // example match: 1.239.14.20220325-164521 9 | versionRegexp = `^(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)$` 10 | binDir = "/agent/bin" 11 | ) 12 | 13 | var ( 14 | log = logd.Get().WithName("oneagent-symlink") 15 | ) 16 | -------------------------------------------------------------------------------- /assets/samples/edgeconnect/edgeconnect.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dynatrace.com/v1alpha2 2 | kind: EdgeConnect 3 | metadata: 4 | name: edge-connect-sample 5 | namespace: dynatrace 6 | spec: 7 | apiServer: "https://example.dev.apps.dynatracelabs.com" 8 | oauth: 9 | clientSecret: my-secret-name 10 | endpoint: https://sso.sample.com/sso/oauth2/token 11 | resource: urn:sample-env:sample-res 12 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/activegate/service.go: -------------------------------------------------------------------------------- 1 | package activegate 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 5 | "github.com/Dynatrace/dynatrace-operator/pkg/controllers/dynakube/activegate/capability" 6 | ) 7 | 8 | func GetServiceFQDN(dk *dynakube.DynaKube) string { 9 | return capability.BuildServiceName(dk.Name) + "." + dk.Namespace 10 | } 11 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/telemetryservice_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/telemetryingest" 5 | ) 6 | 7 | func (dk *DynaKube) TelemetryIngest() *telemetryingest.TelemetryIngest { 8 | ts := &telemetryingest.TelemetryIngest{ 9 | Spec: dk.Spec.TelemetryIngest, 10 | } 11 | ts.SetName(dk.Name) 12 | 13 | return ts 14 | } 15 | -------------------------------------------------------------------------------- /pkg/webhook/config.go: -------------------------------------------------------------------------------- 1 | package webhook 2 | 3 | const ( 4 | // SecretCertsName is the name of the secret where the webhook certificates are stored. 5 | SecretCertsName = "dynatrace-webhook-certs" 6 | 7 | // DeploymentName is the name used for the Deployment of any webhooks and WebhookConfiguration objects. 8 | DeploymentName = "dynatrace-webhook" 9 | 10 | WebhookContainerName = "webhook" 11 | ) 12 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/handler/otlp/config.go: -------------------------------------------------------------------------------- 1 | package otlp 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("pod-mutation-otlp") 9 | ) 10 | 11 | const ( 12 | NoOTLPExporterConfigSecretReason = "NoOTLPExporterConfigSecret" 13 | NoOTLPExporterActiveGateCertSecretReason = "NoOTLPExporterActiveGateCertSecret" 14 | ) 15 | -------------------------------------------------------------------------------- /pkg/api/exp/otlp.go: -------------------------------------------------------------------------------- 1 | package exp 2 | 3 | const ( 4 | OTLPInjectionSetNoProxy = FFPrefix + "otlp-exporter-configuration-set-no-proxy" 5 | ) 6 | 7 | // IsOTLPInjectionSetNoProxy is a feature flag to enable injecting additional environment variables based on user labels. 8 | func (ff *FeatureFlags) IsOTLPInjectionSetNoProxy() bool { 9 | return ff.getBoolWithDefault(OTLPInjectionSetNoProxy, true) 10 | } 11 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/telemetryservice_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta4/dynakube/telemetryingest" 5 | ) 6 | 7 | func (dk *DynaKube) TelemetryIngest() *telemetryingest.TelemetryIngest { 8 | ts := &telemetryingest.TelemetryIngest{ 9 | Spec: dk.Spec.TelemetryIngest, 10 | } 11 | ts.SetName(dk.Name) 12 | 13 | return ts 14 | } 15 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/telemetryservice_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta5/dynakube/telemetryingest" 5 | ) 6 | 7 | func (dk *DynaKube) TelemetryIngest() *telemetryingest.TelemetryIngest { 8 | ts := &telemetryingest.TelemetryIngest{ 9 | Spec: dk.Spec.TelemetryIngest, 10 | } 11 | ts.SetName(dk.Name) 12 | 13 | return ts 14 | } 15 | -------------------------------------------------------------------------------- /pkg/util/envvars/envvars.go: -------------------------------------------------------------------------------- 1 | package envvars 2 | 3 | import ( 4 | "os" 5 | "strconv" 6 | ) 7 | 8 | func GetBool(varName string, defaultValue bool) bool { 9 | envValue := os.Getenv(varName) 10 | if envValue != "" { 11 | parsedValue, err := strconv.ParseBool(envValue) 12 | if err != nil { 13 | return defaultValue 14 | } 15 | 16 | return parsedValue 17 | } 18 | 19 | return defaultValue 20 | } 21 | -------------------------------------------------------------------------------- /hack/build/bin/user_setup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -x 3 | 4 | # ensure $HOME exists and is accessible by group 0 (we don't know what the runtime UID will be) 5 | echo "${USER_NAME}:x:${USER_UID}:0:${USER_NAME} user:${HOME}:/sbin/nologin" >> /etc/passwd 6 | mkdir -p "${HOME}" 7 | chown "${USER_UID}:0" "${HOME}" 8 | chmod ug+rwx "${HOME}" 9 | 10 | # no need for this script to remain in the image after running 11 | rm "$0" 12 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/metadata_enrichment_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/metadataenrichment" 4 | 5 | func (dk *DynaKube) MetadataEnrichment() *metadataenrichment.MetadataEnrichment { 6 | return &metadataenrichment.MetadataEnrichment{ 7 | Spec: &dk.Spec.MetadataEnrichment, 8 | Status: &dk.Status.MetadataEnrichment, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/otlpexporterconfiguration_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/otlp" 4 | 5 | func (dk *DynaKube) OTLPExporterConfiguration() *otlp.ExporterConfiguration { 6 | otlpExporterConfiguration := &otlp.ExporterConfiguration{ 7 | Spec: dk.Spec.OTLPExporterConfiguration, 8 | } 9 | 10 | return otlpExporterConfiguration 11 | } 12 | -------------------------------------------------------------------------------- /config/helm/chart/default/templates/Common/extensions/database/service-account-database.yaml: -------------------------------------------------------------------------------- 1 | {{- if (and .Values.rbac.extensions.database.create .Values.rbac.extensions.create)}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: dynatrace-sql-ext-exec 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | {{- include "dynatrace-operator.databaseDatasourceLabels" . | nindent 4 }} 9 | {{- end }} 10 | -------------------------------------------------------------------------------- /pkg/otelcgen/extensions.go: -------------------------------------------------------------------------------- 1 | package otelcgen 2 | 3 | import "go.opentelemetry.io/collector/component" 4 | 5 | var ( 6 | healthCheck = component.MustNewID("health_check") 7 | ) 8 | 9 | func (c *Config) buildExtensions() map[component.ID]component.Config { 10 | return map[component.ID]component.Config{ 11 | healthCheck: &ServerConfig{ 12 | Endpoint: c.buildEndpoint(ExtensionsHealthCheckPort), 13 | }, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pkg/otlp/exporterconfig/config.go: -------------------------------------------------------------------------------- 1 | package exporterconfig 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/logd" 4 | 5 | var ( 6 | log = logd.Get().WithName("otlp-exporter-configuration") 7 | ) 8 | 9 | // ActiveGateCertDataName is the key used to store ActiveGate certificate data in the secret containing the ActiveGate Certificate for the OTLP exporter. 10 | const ActiveGateCertDataName = "activegate-tls.crt" 11 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/statefulset/builder/builder.go: -------------------------------------------------------------------------------- 1 | package builder 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/util/builder" 5 | appsv1 "k8s.io/api/apps/v1" 6 | ) 7 | 8 | type Data = appsv1.StatefulSet 9 | type Modifier = builder.Modifier[Data] 10 | type Builder = builder.GenericBuilder[Data] 11 | 12 | func NewBuilder(data Data) Builder { 13 | return builder.NewBuilder(data) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/kspm/props.go: -------------------------------------------------------------------------------- 1 | package kspm 2 | 3 | func (kspm *Kspm) SetName(name string) { 4 | kspm.name = name 5 | } 6 | 7 | func (kspm *Kspm) IsEnabled() bool { 8 | return kspm.Spec != nil 9 | } 10 | 11 | func (kspm *Kspm) GetTokenSecretName() string { 12 | return kspm.name + "-" + TokenSecretKey 13 | } 14 | 15 | func (kspm *Kspm) GetDaemonSetName() string { 16 | return kspm.name + "-" + NodeCollectorNameSuffix 17 | } 18 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/kspm/props.go: -------------------------------------------------------------------------------- 1 | package kspm 2 | 3 | func (kspm *Kspm) SetName(name string) { 4 | kspm.name = name 5 | } 6 | 7 | func (kspm *Kspm) IsEnabled() bool { 8 | return kspm.Spec != nil 9 | } 10 | 11 | func (kspm *Kspm) GetTokenSecretName() string { 12 | return kspm.name + "-" + TokenSecretKey 13 | } 14 | 15 | func (kspm *Kspm) GetDaemonSetName() string { 16 | return kspm.name + "-" + NodeCollectorNameSuffix 17 | } 18 | -------------------------------------------------------------------------------- /pkg/api/validation/dynakube/config.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const oneagentEnableVolumeStorageEnvVarName = "ONEAGENT_ENABLE_VOLUME_STORAGE" 8 | const oneagentInstallerScriptURLEnvVarName = "ONEAGENT_INSTALLER_SCRIPT_URL" 9 | const oneagentInstallerTokenEnvVarName = "ONEAGENT_INSTALLER_TOKEN" 10 | 11 | var log = logd.Get().WithName("dynakube-validation") 12 | -------------------------------------------------------------------------------- /config/helm/chart/default/app-readme.md: -------------------------------------------------------------------------------- 1 | # Dynatrace Operator 2 | 3 | The Dynatrace Operator supports rollout and lifecycle of various Dynatrace components in Kubernetes and OpenShift. 4 | 5 | As of launch, the Dynatrace Operator can be used to deploy a containerized ActiveGate for Kubernetes API monitoring. New capabilities will be added to the Dynatrace Operator over time including metric routing, and API monitoring for AWS, Azure, GCP, and vSphere. 6 | -------------------------------------------------------------------------------- /hack/make/deploy/cleanup.mk: -------------------------------------------------------------------------------- 1 | 2 | ## Remove all Dynatrace Operator resources from the cluster and node filesystem 3 | cleanup: cleanup/cluster cleanup/node-fs 4 | 5 | ## Remove all Dynatrace Operator resources from the cluster 6 | cleanup/cluster: 7 | @./hack/cluster/cleanup-dynatrace-objects.sh 8 | 9 | ## Remove node filesystem leftovers 10 | cleanup/node-fs: 11 | @SKIP_RUNNING_PODS_WARNING=true ./hack/cluster/cleanup-node-fs.sh dynatrace 12 | -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. 2 | version: v1.25.1 3 | # ignores vulnerabilities until expiry date; change duration by modifying expiry date 4 | ignore: 5 | 'snyk:lic:golang:github.com:hashicorp:go-version:MPL-2.0': 6 | - '*': 7 | reason: MPL-2.0 is allowed to be used with APACHE-2.0 8 | expires: 2028-07-29T00:00:00.000Z 9 | created: 2025-07-29T14:55:34.428Z 10 | patch: {} 11 | -------------------------------------------------------------------------------- /config/helm/chart/default/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Thank you for installing {{ .Chart.Name }}. 2 | 3 | Your release is named {{ .Release.Name }}. 4 | 5 | To find more information about the Dynatrace Operator, try: 6 | https://github.com/Dynatrace/dynatrace-operator 7 | 8 | To verify the current state of the deployments, try: 9 | $ kubectl get pods -n {{ .Release.Namespace }} 10 | $ kubectl logs -f deployment/dynatrace-operator -n {{ .Release.Namespace }} 11 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/metadata_enrichment_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | ) 6 | 7 | func (dk *DynaKube) MetadataEnrichmentEnabled() bool { 8 | return dk.Spec.MetadataEnrichment.Enabled != nil && *dk.Spec.MetadataEnrichment.Enabled 9 | } 10 | 11 | func (dk *DynaKube) MetadataEnrichmentNamespaceSelector() *metav1.LabelSelector { 12 | return &dk.Spec.MetadataEnrichment.NamespaceSelector 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/metadata_enrichment_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | ) 6 | 7 | func (dk *DynaKube) MetadataEnrichmentEnabled() bool { 8 | return dk.Spec.MetadataEnrichment.Enabled != nil && *dk.Spec.MetadataEnrichment.Enabled 9 | } 10 | 11 | func (dk *DynaKube) MetadataEnrichmentNamespaceSelector() *metav1.LabelSelector { 12 | return &dk.Spec.MetadataEnrichment.NamespaceSelector 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/metadata_enrichment_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | ) 6 | 7 | func (dk *DynaKube) MetadataEnrichmentEnabled() bool { 8 | return dk.Spec.MetadataEnrichment.Enabled != nil && *dk.Spec.MetadataEnrichment.Enabled 9 | } 10 | 11 | func (dk *DynaKube) MetadataEnrichmentNamespaceSelector() *metav1.LabelSelector { 12 | return &dk.Spec.MetadataEnrichment.NamespaceSelector 13 | } 14 | -------------------------------------------------------------------------------- /test/helpers/shell/shell_test.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package shell 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestStringifier(t *testing.T) { 12 | assert.Equal(t, "du -c /foobar", DiskUsageWithTotal("/foobar").String()) 13 | assert.Equal(t, "tail -n 1", FilterLastLineOnly().String()) 14 | assert.Equal(t, "du -c /foobar | tail -n 1", Pipe(DiskUsageWithTotal("/foobar"), FilterLastLineOnly()).String()) 15 | } 16 | -------------------------------------------------------------------------------- /hack/build/ci/push-helm-chart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | readonly PATH_TO_HELM_CHART="${1}" 4 | readonly REGISTRY_URL="${2}" 5 | 6 | output=$(helm push "${PATH_TO_HELM_CHART}" "${REGISTRY_URL}" 2>&1) 7 | exit_status=$? 8 | 9 | if [ $exit_status -eq 0 ]; then 10 | digest=$(echo "$output" | awk '/Digest:/ {print $2}') 11 | echo "digest=$digest" >> $GITHUB_OUTPUT 12 | else 13 | echo "Command failed with exit status $exit_status. Error: $output" 14 | exit $exit_status 15 | fi 16 | -------------------------------------------------------------------------------- /pkg/otlp/exporterconfig/replicate.go: -------------------------------------------------------------------------------- 1 | package exporterconfig 2 | 3 | import "fmt" 4 | 5 | const ( 6 | sourceSecretTemplate = "%s-otlp-exporter-config" 7 | sourceSecretCertsTemplate = "%s-otlp-exporter-certs" 8 | ) 9 | 10 | func GetSourceConfigSecretName(dkName string) string { 11 | return fmt.Sprintf(sourceSecretTemplate, dkName) 12 | } 13 | 14 | func GetSourceCertsSecretName(dkName string) string { 15 | return fmt.Sprintf(sourceSecretCertsTemplate, dkName) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/dynakube_webhook.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | ctrl "sigs.k8s.io/controller-runtime" 5 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 6 | ) 7 | 8 | func SetupWebhookWithManager(mgr ctrl.Manager, validator admission.CustomValidator) error { 9 | return ctrl.NewWebhookManagedBy(mgr). 10 | For(&DynaKube{}). 11 | WithValidator(validator). // will create an endpoint at /validate-dynatrace-com-v1beta6-dynakube 12 | Complete() 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/kspm_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/kspm" 4 | 5 | func (dk *DynaKube) KSPM() *kspm.Kspm { 6 | _kspm := &kspm.Kspm{ 7 | Spec: dk.Spec.Kspm, 8 | Status: &dk.Status.Kspm, 9 | NodeConfigurationCollectorSpec: &dk.Spec.Templates.KspmNodeConfigurationCollector, 10 | } 11 | _kspm.SetName(dk.GetName()) 12 | 13 | return _kspm 14 | } 15 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/dynakube_webhook.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | ctrl "sigs.k8s.io/controller-runtime" 5 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 6 | ) 7 | 8 | func SetupWebhookWithManager(mgr ctrl.Manager, validator admission.CustomValidator) error { 9 | return ctrl.NewWebhookManagedBy(mgr). 10 | For(&DynaKube{}). 11 | WithValidator(validator). // will create an endpoint at /validate-dynatrace-com-v1beta3-dynakube 12 | Complete() 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/kspm_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta3/dynakube/kspm" 4 | 5 | func (dk *DynaKube) KSPM() *kspm.Kspm { 6 | _kspm := &kspm.Kspm{ 7 | Spec: dk.Spec.Kspm, 8 | Status: &dk.Status.Kspm, 9 | NodeConfigurationCollectorSpec: &dk.Spec.Templates.KspmNodeConfigurationCollector, 10 | } 11 | _kspm.SetName(dk.GetName()) 12 | 13 | return _kspm 14 | } 15 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/dynakube_webhook.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | ctrl "sigs.k8s.io/controller-runtime" 5 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 6 | ) 7 | 8 | func SetupWebhookWithManager(mgr ctrl.Manager, validator admission.CustomValidator) error { 9 | return ctrl.NewWebhookManagedBy(mgr). 10 | For(&DynaKube{}). 11 | WithValidator(validator). // will create an endpoint at /validate-dynatrace-com-v1beta4-dynakube 12 | Complete() 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/kspm_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta4/dynakube/kspm" 4 | 5 | func (dk *DynaKube) KSPM() *kspm.Kspm { 6 | _kspm := &kspm.Kspm{ 7 | Spec: dk.Spec.Kspm, 8 | Status: &dk.Status.Kspm, 9 | NodeConfigurationCollectorSpec: &dk.Spec.Templates.KspmNodeConfigurationCollector, 10 | } 11 | _kspm.SetName(dk.GetName()) 12 | 13 | return _kspm 14 | } 15 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/dynakube_webhook.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | ctrl "sigs.k8s.io/controller-runtime" 5 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 6 | ) 7 | 8 | func SetupWebhookWithManager(mgr ctrl.Manager, validator admission.CustomValidator) error { 9 | return ctrl.NewWebhookManagedBy(mgr). 10 | For(&DynaKube{}). 11 | WithValidator(validator). // will create an endpoint at /validate-dynatrace-com-v1beta5-dynakube 12 | Complete() 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/kspm_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta5/dynakube/kspm" 4 | 5 | func (dk *DynaKube) KSPM() *kspm.Kspm { 6 | _kspm := &kspm.Kspm{ 7 | Spec: dk.Spec.Kspm, 8 | Status: &dk.Status.Kspm, 9 | NodeConfigurationCollectorSpec: &dk.Spec.Templates.KspmNodeConfigurationCollector, 10 | } 11 | _kspm.SetName(dk.GetName()) 12 | 13 | return _kspm 14 | } 15 | -------------------------------------------------------------------------------- /pkg/api/validation/dynakube/istio_test.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 7 | ) 8 | 9 | func TestNoResourcesAvailable(t *testing.T) { 10 | t.Run("no resources", func(t *testing.T) { 11 | assertDenied(t, []string{errorNoResources}, &dynakube.DynaKube{ 12 | Spec: dynakube.DynaKubeSpec{ 13 | APIURL: testAPIURL, 14 | EnableIstio: true, 15 | }, 16 | }) 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /pkg/otelcgen/testdata/services_zipkin_only.yaml: -------------------------------------------------------------------------------- 1 | connectors: {} 2 | exporters: {} 3 | extensions: {} 4 | processors: {} 5 | receivers: {} 6 | service: 7 | extensions: 8 | - health_check 9 | pipelines: 10 | traces: 11 | exporters: 12 | - otlphttp 13 | receivers: 14 | - zipkin 15 | processors: 16 | - memory_limiter 17 | - transform/add-pod-ip 18 | - k8sattributes 19 | - transform 20 | - batch/traces 21 | -------------------------------------------------------------------------------- /test/helpers/kubeobjects/environment/environment.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package environment 4 | 5 | import ( 6 | _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" 7 | "sigs.k8s.io/e2e-framework/klient/conf" 8 | "sigs.k8s.io/e2e-framework/pkg/envconf" 9 | ) 10 | 11 | func GetStandardKubeClusterEnvConfig() *envconf.Config { 12 | kubeConfigPath := conf.ResolveKubeConfigFile() 13 | cfg, _ := envconf.NewFromFlags() 14 | 15 | return cfg.WithKubeconfigFile(kubeConfigPath) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/oneagent_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta3/dynakube/oneagent" 5 | ) 6 | 7 | func (dk *DynaKube) OneAgent() *oneagent.OneAgent { 8 | oa := oneagent.NewOneAgent( 9 | &dk.Spec.OneAgent, 10 | &dk.Status.OneAgent, 11 | &dk.Status.CodeModules, 12 | dk.Name, 13 | dk.ApiUrlHost(), 14 | dk.FF().IsOneAgentPrivileged(), 15 | dk.FF().SkipOneAgentLivenessProbe()) 16 | 17 | return oa 18 | } 19 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/handler/injection/deprecated.go: -------------------------------------------------------------------------------- 1 | package injection 2 | 3 | import podattr "github.com/Dynatrace/dynatrace-bootstrapper/cmd/configure/attributes/pod" 4 | 5 | const ( 6 | deprecatedClusterIDKey = "dt.kubernetes.cluster.id" 7 | ) 8 | 9 | func setDeprecatedAttributes(attrs *podattr.Attributes) { 10 | if attrs.UserDefined == nil { 11 | attrs.UserDefined = map[string]string{} 12 | } 13 | 14 | attrs.UserDefined[deprecatedClusterIDKey] = attrs.ClusterUID 15 | } 16 | -------------------------------------------------------------------------------- /test/helpers/components/webhook/deployment.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package webhook 4 | 5 | import ( 6 | "github.com/Dynatrace/dynatrace-operator/pkg/webhook" 7 | "github.com/Dynatrace/dynatrace-operator/test/helpers/kubeobjects/deployment" 8 | "sigs.k8s.io/e2e-framework/pkg/env" 9 | ) 10 | 11 | const ( 12 | DeploymentName = webhook.DeploymentName 13 | ) 14 | 15 | func WaitForDeployment(namespace string) env.Func { 16 | return deployment.WaitFor(DeploymentName, namespace) 17 | } 18 | -------------------------------------------------------------------------------- /hack/make/manifests/manifests.mk: -------------------------------------------------------------------------------- 1 | manifests/prepare-directory: 2 | find $(MANIFESTS_DIR) -type f -not -name 'kustomization.yaml' -delete 3 | 4 | ## Generates manifests e.g. CRD, RBAC etc, for Kubernetes and OpenShift 5 | manifests: manifests/prepare-directory manifests/kubernetes manifests/openshift manifests/deepcopy 6 | 7 | ## Generate deep copy files 8 | manifests/deepcopy: prerequisites/controller-gen 9 | $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./pkg/api/..." 10 | -------------------------------------------------------------------------------- /pkg/api/v1alpha1/edgeconnect/edgeconnect_webhook.go: -------------------------------------------------------------------------------- 1 | package edgeconnect 2 | 3 | import ( 4 | ctrl "sigs.k8s.io/controller-runtime" 5 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 6 | ) 7 | 8 | func SetupWebhookWithManager(mgr ctrl.Manager, validator admission.CustomValidator) error { 9 | return ctrl.NewWebhookManagedBy(mgr). 10 | For(&EdgeConnect{}). 11 | WithValidator(validator). // will create an endpoint at /validate-dynatrace-com-v1alpha1-edgeconnect 12 | Complete() 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/v1alpha2/edgeconnect/edgeconnect_webhook.go: -------------------------------------------------------------------------------- 1 | package edgeconnect 2 | 3 | import ( 4 | ctrl "sigs.k8s.io/controller-runtime" 5 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 6 | ) 7 | 8 | func SetupWebhookWithManager(mgr ctrl.Manager, validator admission.CustomValidator) error { 9 | return ctrl.NewWebhookManagedBy(mgr). 10 | For(&EdgeConnect{}). 11 | WithValidator(validator). // will create an endpoint at /validate-dynatrace-com-v1alpha2-edgeconnect 12 | Complete() 13 | } 14 | -------------------------------------------------------------------------------- /pkg/injection/namespace/mapper/config.go: -------------------------------------------------------------------------------- 1 | package mapper 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const ( 8 | UpdatedViaDynakubeAnnotation = "dynatrace.com/updated-via-operator" 9 | ErrorConflictingNamespace = "namespace matches two or more DynaKubes which is unsupported. " + 10 | "refine the labels on your namespace metadata or DynaKube/CodeModules specification" 11 | ) 12 | 13 | var ( 14 | log = logd.Get().WithName("namespace-mapper") 15 | ) 16 | -------------------------------------------------------------------------------- /config/helm/chart/default/.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 | 25 | tests/ 26 | -------------------------------------------------------------------------------- /test/helpers/components/operator/deployment.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package operator 4 | 5 | import ( 6 | "github.com/Dynatrace/dynatrace-operator/test/helpers/kubeobjects/deployment" 7 | "sigs.k8s.io/e2e-framework/pkg/env" 8 | ) 9 | 10 | const ( 11 | DeploymentName = "dynatrace-operator" 12 | ContainerName = "operator" 13 | DefaultNamespace = "dynatrace" 14 | ) 15 | 16 | func WaitForDeployment(namespace string) env.Func { 17 | return deployment.WaitFor(DeploymentName, namespace) 18 | } 19 | -------------------------------------------------------------------------------- /cmd/supportarchive/resource_query_test.go: -------------------------------------------------------------------------------- 1 | package supportarchive 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | const namespace = "dynatrace" 10 | 11 | func TestObjectQuerySyntax(t *testing.T) { 12 | queries := getQueries(namespace, defaultOperatorAppName) 13 | assert.Len(t, queries, 18) 14 | 15 | for _, query := range queries { 16 | assert.NotEmpty(t, query.groupVersionKind.Kind) 17 | assert.NotEmpty(t, query.groupVersionKind.Version) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /hack/kind/cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kind.x-k8s.io/v1alpha4 2 | kind: Cluster 3 | kubeadmConfigPatches: 4 | - | 5 | kind: ClusterConfiguration 6 | metadata: 7 | name: config 8 | etcd: 9 | local: 10 | extraArgs: 11 | unsafe-no-fsync: "true" # etcd performance improvement for CI only by removing the overhead of forcing data to disk but is unsafe for production because it can lead to data loss and corruption if the system crashes. 12 | nodes: 13 | - role: control-plane 14 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/logmonitoring_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/logmonitoring" 5 | ) 6 | 7 | func (dk *DynaKube) LogMonitoring() *logmonitoring.LogMonitoring { 8 | lm := &logmonitoring.LogMonitoring{ 9 | Spec: dk.Spec.LogMonitoring, 10 | TemplateSpec: dk.Spec.Templates.LogMonitoring, 11 | } 12 | lm.SetName(dk.Name) 13 | lm.SetHostAgentDependency(dk.OneAgent().IsDaemonsetRequired()) 14 | 15 | return lm 16 | } 17 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/logmonitoring/daemonset/annotations.go: -------------------------------------------------------------------------------- 1 | package daemonset 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api" 5 | "github.com/Dynatrace/dynatrace-operator/pkg/controllers/dynakube/logmonitoring/configsecret" 6 | ) 7 | 8 | const annotationTenantTokenHash = api.InternalFlagPrefix + "tenant-token-hash" 9 | 10 | func (r *Reconciler) getAnnotations() map[string]string { 11 | return configsecret.AddAnnotations(r.dk.LogMonitoring().Template().Annotations, *r.dk) 12 | } 13 | -------------------------------------------------------------------------------- /hack/build/push_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ ! "${1}" ]]; then 4 | echo "first param is not set, should be the image without the tag" 5 | exit 1 6 | fi 7 | if [[ ! "${2}" ]]; then 8 | echo "second param is not set, should be the tag of the image" 9 | exit 1 10 | fi 11 | image=${1} 12 | tag=${2} 13 | 14 | out_image="${image}:${tag}" 15 | 16 | if ! command -v docker 2>/dev/null; then 17 | CONTAINER_CMD=podman 18 | else 19 | CONTAINER_CMD=docker 20 | fi 21 | 22 | ${CONTAINER_CMD} push "${out_image}" 23 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/logmonitoring_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta3/dynakube/logmonitoring" 5 | ) 6 | 7 | func (dk *DynaKube) LogMonitoring() *logmonitoring.LogMonitoring { 8 | lm := &logmonitoring.LogMonitoring{ 9 | Spec: dk.Spec.LogMonitoring, 10 | TemplateSpec: dk.Spec.Templates.LogMonitoring, 11 | } 12 | lm.SetName(dk.Name) 13 | lm.SetHostAgentDependency(dk.OneAgent().IsDaemonsetRequired()) 14 | 15 | return lm 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/logmonitoring_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta4/dynakube/logmonitoring" 5 | ) 6 | 7 | func (dk *DynaKube) LogMonitoring() *logmonitoring.LogMonitoring { 8 | lm := &logmonitoring.LogMonitoring{ 9 | Spec: dk.Spec.LogMonitoring, 10 | TemplateSpec: dk.Spec.Templates.LogMonitoring, 11 | } 12 | lm.SetName(dk.Name) 13 | lm.SetHostAgentDependency(dk.OneAgent().IsDaemonsetRequired()) 14 | 15 | return lm 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/logmonitoring_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta5/dynakube/logmonitoring" 5 | ) 6 | 7 | func (dk *DynaKube) LogMonitoring() *logmonitoring.LogMonitoring { 8 | lm := &logmonitoring.LogMonitoring{ 9 | Spec: dk.Spec.LogMonitoring, 10 | TemplateSpec: dk.Spec.Templates.LogMonitoring, 11 | } 12 | lm.SetName(dk.Name) 13 | lm.SetHostAgentDependency(dk.OneAgent().IsDaemonsetRequired()) 14 | 15 | return lm 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/validation/message.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func SumErrors(validationErrors []string, customResourceType string) string { 9 | var summedErrors strings.Builder 10 | summedErrors.WriteString(fmt.Sprintf("\n%d error(s) found in the %s", len(validationErrors), customResourceType)) 11 | 12 | for i, errMsg := range validationErrors { 13 | summedErrors.WriteString(fmt.Sprintf("\n %d. %s", i+1, errMsg)) 14 | } 15 | 16 | return summedErrors.String() 17 | } 18 | -------------------------------------------------------------------------------- /pkg/otelcgen/testdata/services_statsd_only.yaml: -------------------------------------------------------------------------------- 1 | connectors: {} 2 | exporters: {} 3 | extensions: {} 4 | processors: {} 5 | receivers: {} 6 | service: 7 | extensions: 8 | - health_check 9 | pipelines: 10 | metrics: 11 | exporters: 12 | - otlphttp 13 | receivers: 14 | - statsd 15 | processors: 16 | - memory_limiter 17 | - transform/add-pod-ip 18 | - k8sattributes 19 | - transform 20 | - cumulativetodelta 21 | - batch/metrics 22 | -------------------------------------------------------------------------------- /hack/build/command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cmd="${1}" 5 | 6 | # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) 7 | if [ "$(go env GOBIN)" = "" ]; then 8 | GOBIN="$(go env GOPATH)/bin" 9 | else 10 | GOBIN="$(go env GOBIN)" 11 | fi 12 | 13 | if [ -x "${GOBIN}/${cmd}" ]; then 14 | echo "${GOBIN}/${cmd}" 15 | exit 0 16 | fi 17 | 18 | if which "${cmd}" &>/dev/null ; then 19 | which "${cmd}" 2>/dev/null 20 | exit 0 21 | fi 22 | 23 | # The command hasn't been found 24 | exit 1 25 | -------------------------------------------------------------------------------- /hack/make/markdown.mk: -------------------------------------------------------------------------------- 1 | ## Runs markdownlint using existing .markdownlint.json config file through all .md files in the project 2 | markdown/lint: prerequisites/markdownlint 3 | # --disable MD034 MD037 - workaround for errors in k8s.io/api package (type PersistentVolumeClaimSpec) 4 | $(MARKDOWNLINT) --ignore node_modules --disable MD034 MD037 -- . 5 | 6 | ## Runs markdown-link-check for all .md files in the project 7 | markdown/link-check: prerequisites/markdown-link-check 8 | $(MARKDOWN_LINK_CHECK) --ignore node_modules,.git,testdata . 9 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/oneagent_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/oneagent" 5 | ) 6 | 7 | func (dk *DynaKube) OneAgent() *oneagent.OneAgent { 8 | oa := oneagent.NewOneAgent( 9 | &dk.Spec.OneAgent, 10 | &dk.Status.OneAgent, 11 | &dk.Status.CodeModules, 12 | dk.Name, 13 | dk.APIURLHost(), 14 | dk.FF().IsOneAgentPrivileged(), 15 | dk.FF().SkipOneAgentLivenessProbe(), 16 | dk.FF().IsNodeImagePull(), 17 | ) 18 | 19 | return oa 20 | } 21 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/telemetryingest/spec.go: -------------------------------------------------------------------------------- 1 | package telemetryingest 2 | 3 | type TelemetryIngest struct { 4 | *Spec 5 | 6 | name string 7 | } 8 | 9 | // +kubebuilder:object:generate=true 10 | 11 | type Spec struct { 12 | // +kubebuilder:validation:Optional 13 | ServiceName string `json:"serviceName,omitempty"` 14 | 15 | // +kubebuilder:validation:Optional 16 | TLSRefName string `json:"tlsRefName,omitempty"` 17 | 18 | // +kubebuilder:validation:Optional 19 | Protocols []string `json:"protocols,omitempty"` 20 | } 21 | -------------------------------------------------------------------------------- /pkg/util/functional/map_test.go: -------------------------------------------------------------------------------- 1 | package functional 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMap(t *testing.T) { 10 | t.Run("map slice of struct to slice of strings", func(t *testing.T) { 11 | type Foo struct { 12 | S string 13 | } 14 | 15 | foos := []Foo{{S: "aaa"}, {S: "bbb"}} 16 | actual := Map(foos, func(f Foo) string { 17 | return f.S 18 | }) 19 | expected := []string{"aaa", "bbb"} 20 | 21 | assert.Equal(t, expected, actual) 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/oneagent_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta4/dynakube/oneagent" 5 | ) 6 | 7 | func (dk *DynaKube) OneAgent() *oneagent.OneAgent { 8 | oa := oneagent.NewOneAgent( 9 | &dk.Spec.OneAgent, 10 | &dk.Status.OneAgent, 11 | &dk.Status.CodeModules, 12 | dk.Name, 13 | dk.APIURLHost(), 14 | dk.FF().IsOneAgentPrivileged(), 15 | dk.FF().SkipOneAgentLivenessProbe(), 16 | dk.FF().IsNodeImagePull(), 17 | ) 18 | 19 | return oa 20 | } 21 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/telemetryingest/spec.go: -------------------------------------------------------------------------------- 1 | package telemetryingest 2 | 3 | type TelemetryIngest struct { 4 | *Spec 5 | 6 | name string 7 | } 8 | 9 | // +kubebuilder:object:generate=true 10 | 11 | type Spec struct { 12 | // +kubebuilder:validation:Optional 13 | ServiceName string `json:"serviceName,omitempty"` 14 | 15 | // +kubebuilder:validation:Optional 16 | TLSRefName string `json:"tlsRefName,omitempty"` 17 | 18 | // +kubebuilder:validation:Optional 19 | Protocols []string `json:"protocols,omitempty"` 20 | } 21 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/oneagent_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta5/dynakube/oneagent" 5 | ) 6 | 7 | func (dk *DynaKube) OneAgent() *oneagent.OneAgent { 8 | oa := oneagent.NewOneAgent( 9 | &dk.Spec.OneAgent, 10 | &dk.Status.OneAgent, 11 | &dk.Status.CodeModules, 12 | dk.Name, 13 | dk.APIURLHost(), 14 | dk.FF().IsOneAgentPrivileged(), 15 | dk.FF().SkipOneAgentLivenessProbe(), 16 | dk.FF().IsNodeImagePull(), 17 | ) 18 | 19 | return oa 20 | } 21 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/telemetryingest/spec.go: -------------------------------------------------------------------------------- 1 | package telemetryingest 2 | 3 | type TelemetryIngest struct { 4 | *Spec 5 | 6 | name string 7 | } 8 | 9 | // +kubebuilder:object:generate=true 10 | 11 | type Spec struct { 12 | // +kubebuilder:validation:Optional 13 | ServiceName string `json:"serviceName,omitempty"` 14 | 15 | // +kubebuilder:validation:Optional 16 | TLSRefName string `json:"tlsRefName,omitempty"` 17 | 18 | // +kubebuilder:validation:Optional 19 | Protocols []string `json:"protocols,omitempty"` 20 | } 21 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/arg/arg.go: -------------------------------------------------------------------------------- 1 | package arg 2 | 3 | import "fmt" 4 | 5 | type Arg struct { 6 | Name string 7 | Value string 8 | } 9 | 10 | func (a Arg) String() string { 11 | if a.Value == "" { 12 | return "--" + a.Name 13 | } 14 | 15 | return fmt.Sprintf("--%s=%s", a.Name, a.Value) 16 | } 17 | 18 | func ConvertArgsToStrings(args []Arg) []string { 19 | convertedArgs := make([]string, len(args)) 20 | for i, arg := range args { 21 | convertedArgs[i] = arg.String() 22 | } 23 | 24 | return convertedArgs 25 | } 26 | -------------------------------------------------------------------------------- /test/helpers/kubeobjects/pod/list.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package pod 4 | 5 | import ( 6 | "context" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | corev1 "k8s.io/api/core/v1" 11 | "sigs.k8s.io/e2e-framework/klient/k8s/resources" 12 | ) 13 | 14 | func List(t *testing.T, ctx context.Context, resource *resources.Resources, namespaceName string) corev1.PodList { 15 | var pods corev1.PodList 16 | 17 | require.NoError(t, resource.WithNamespace(namespaceName).List(ctx, &pods)) 18 | 19 | return pods 20 | } 21 | -------------------------------------------------------------------------------- /pkg/util/kubernetes/fields/k8sresource/resources.go: -------------------------------------------------------------------------------- 1 | package k8sresource 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | "k8s.io/apimachinery/pkg/api/resource" 6 | ) 7 | 8 | func NewResourceList(cpu, memory string) corev1.ResourceList { 9 | return corev1.ResourceList{ 10 | corev1.ResourceCPU: *NewQuantity(cpu), 11 | corev1.ResourceMemory: *NewQuantity(memory), 12 | } 13 | } 14 | 15 | func NewQuantity(serialized string) *resource.Quantity { 16 | parsed := resource.MustParse(serialized) 17 | 18 | return &parsed 19 | } 20 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/handler/injection/config.go: -------------------------------------------------------------------------------- 1 | package injection 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | var ( 8 | log = logd.Get().WithName("pod-mutation-injection") 9 | ) 10 | 11 | const ( 12 | K8sNodeNameEnv = "K8S_NODE_NAME" 13 | K8sPodNameEnv = "K8S_PODNAME" 14 | K8sPodUIDEnv = "K8S_PODUID" 15 | 16 | NoBootstrapperConfigReason = "NoBootstrapperConfig" 17 | NoMutationNeededReason = "NoMutationNeeded" 18 | 19 | RootUser int64 = 0 20 | RootGroup int64 = 0 21 | ) 22 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/otelc_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | func (dk *DynaKube) OtelCollectorStatefulsetName() string { 4 | return dk.Name + "-otel-collector" 5 | } 6 | 7 | func (dk *DynaKube) IsAGCertificateNeeded() bool { 8 | if dk.ActiveGate().IsEnabled() && dk.ActiveGate().HasCaCert() { 9 | return true 10 | } 11 | 12 | return false 13 | } 14 | 15 | func (dk *DynaKube) IsCACertificateNeeded() bool { 16 | if !dk.ActiveGate().IsEnabled() && dk.Spec.TrustedCAs != "" { 17 | return true 18 | } 19 | 20 | return false 21 | } 22 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/otelc_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | func (dk *DynaKube) OtelCollectorStatefulsetName() string { 4 | return dk.Name + "-otel-collector" 5 | } 6 | 7 | func (dk *DynaKube) IsAGCertificateNeeded() bool { 8 | if dk.ActiveGate().IsEnabled() && dk.ActiveGate().HasCaCert() { 9 | return true 10 | } 11 | 12 | return false 13 | } 14 | 15 | func (dk *DynaKube) IsCACertificateNeeded() bool { 16 | if !dk.ActiveGate().IsEnabled() && dk.Spec.TrustedCAs != "" { 17 | return true 18 | } 19 | 20 | return false 21 | } 22 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/otelc_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | func (dk *DynaKube) OtelCollectorStatefulsetName() string { 4 | return dk.Name + "-otel-collector" 5 | } 6 | 7 | func (dk *DynaKube) IsAGCertificateNeeded() bool { 8 | if dk.ActiveGate().IsEnabled() && dk.ActiveGate().HasCaCert() { 9 | return true 10 | } 11 | 12 | return false 13 | } 14 | 15 | func (dk *DynaKube) IsCACertificateNeeded() bool { 16 | if !dk.ActiveGate().IsEnabled() && dk.Spec.TrustedCAs != "" { 17 | return true 18 | } 19 | 20 | return false 21 | } 22 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - cherrypick 5 | categories: 6 | - title: Bugfixes 🪲 7 | labels: 8 | - bug 9 | - title: Core changes 🎉 10 | labels: 11 | - core 12 | - ci 13 | - security 14 | - title: Helm changes ⛑️ 15 | labels: 16 | - helm 17 | - title: Component changes 🛠️ 18 | labels: 19 | - oneagent 20 | - activegate 21 | - title: Documentation changes 📚 22 | labels: 23 | - documentation 24 | -------------------------------------------------------------------------------- /hack/gcr/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | export REGISTRY=gcr.io/dynatrace-marketplace-dev 6 | export APP_NAME=dynatrace-operator 7 | TAG="${1:-""}" 8 | PLATFORM="${2:-"google-marketplace"}" 9 | 10 | if ! kubectl create namespace test-ns; then 11 | kubectl delete namespace test-ns 12 | kubectl create namespace test-ns 13 | fi 14 | 15 | mpdev install \ 16 | --deployer="$REGISTRY/$APP_NAME/deployer${TAG}" \ 17 | --parameters="{\"name\": \"test-deployment\", \"namespace\": \"test-ns\", \"platform\": \"${PLATFORM}\"}" 18 | -------------------------------------------------------------------------------- /hack/helm/lint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "Linting helm chart" 3 | if ! helm template --debug ./config/helm/chart/default/ --set platform=google-marketplace --set installCRD=true --set csidriver.enabled=true; then 4 | echo "could not parse template. something is wrong with template files" 5 | exit 10 6 | fi 7 | if ! helm lint --debug ./config/helm/chart/default/ --set platform=google-marketplace --set installCRD=true --set csidriver.enabled=true; then 8 | echo "linter returned with error. check yaml formatting in files" 9 | exit 15 10 | fi 11 | -------------------------------------------------------------------------------- /test/helpers/kubeobjects/service/list.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package service 4 | 5 | import ( 6 | "context" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | corev1 "k8s.io/api/core/v1" 11 | "sigs.k8s.io/e2e-framework/klient/k8s/resources" 12 | ) 13 | 14 | func List(t *testing.T, ctx context.Context, resource *resources.Resources, namespaceName string) corev1.ServiceList { 15 | var services corev1.ServiceList 16 | require.NoError(t, resource.WithNamespace(namespaceName).List(ctx, &services)) 17 | 18 | return services 19 | } 20 | -------------------------------------------------------------------------------- /pkg/api/validation/edgeconnect/module.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1alpha2/edgeconnect" 7 | "github.com/Dynatrace/dynatrace-operator/pkg/util/installconfig" 8 | ) 9 | 10 | var ( 11 | errorModuleDisabled = installconfig.GetModuleValidationErrorMessage("EdgeConnect") 12 | ) 13 | 14 | func isModuleDisabled(_ context.Context, v *Validator, _ *edgeconnect.EdgeConnect) string { 15 | if v.modules.EdgeConnect { 16 | return "" 17 | } 18 | 19 | return errorModuleDisabled 20 | } 21 | -------------------------------------------------------------------------------- /pkg/api/validation/edgeconnect/service_account.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1alpha2/edgeconnect" 7 | ) 8 | 9 | const ( 10 | errorInvalidServiceName = `The EdgeConnect's specification has an invalid serviceAccountName. 11 | ` 12 | ) 13 | 14 | func isInvalidServiceName(_ context.Context, _ *Validator, edgeConnectCR *edgeconnect.EdgeConnect) string { 15 | if edgeConnectCR.GetServiceAccountName() == "" { 16 | return errorInvalidServiceName 17 | } 18 | 19 | return "" 20 | } 21 | -------------------------------------------------------------------------------- /hack/make/helm/version.mk: -------------------------------------------------------------------------------- 1 | ## Sets the Helm Charts version and appVersion 2 | helm/version: 3 | ifneq ($(CHART_VERSION),) 4 | sed "s/^version: .*/version: $(CHART_VERSION)/" $(HELM_CHART_DEFAULT_DIR)/Chart.yaml > $(HELM_CHART_DEFAULT_DIR)/Chart.yaml.output 5 | mv $(HELM_CHART_DEFAULT_DIR)/Chart.yaml.output $(HELM_CHART_DEFAULT_DIR)/Chart.yaml 6 | sed "s/^appVersion: .*/appVersion: $(CHART_VERSION)/" $(HELM_CHART_DEFAULT_DIR)/Chart.yaml > $(HELM_CHART_DEFAULT_DIR)/Chart.yaml.output 7 | mv $(HELM_CHART_DEFAULT_DIR)/Chart.yaml.output $(HELM_CHART_DEFAULT_DIR)/Chart.yaml 8 | endif 9 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/mutator/errors.go: -------------------------------------------------------------------------------- 1 | package mutator 2 | 3 | import corev1 "k8s.io/api/core/v1" 4 | 5 | //nolint:revive // The mutator package is always aliased so this name doesn't stutter. 6 | type MutatorError struct { 7 | Err error 8 | Annotate func(*corev1.Pod) 9 | } 10 | 11 | func (e MutatorError) Error() string { 12 | return e.Err.Error() 13 | } 14 | 15 | func (e MutatorError) Unwrap() error { 16 | return e.Err 17 | } 18 | 19 | func (e MutatorError) SetAnnotations(pod *corev1.Pod) { 20 | if e.Annotate != nil { 21 | e.Annotate(pod) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/helpers/kubeobjects/event/list.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package event 4 | 5 | import ( 6 | "context" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | corev1 "k8s.io/api/core/v1" 11 | "sigs.k8s.io/e2e-framework/klient/k8s/resources" 12 | ) 13 | 14 | func List(t *testing.T, ctx context.Context, resource *resources.Resources, namespace string, listOpt resources.ListOption) corev1.EventList { 15 | var events corev1.EventList 16 | 17 | require.NoError(t, resource.WithNamespace(namespace).List(ctx, &events, listOpt)) 18 | 19 | return events 20 | } 21 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/istio/config.go: -------------------------------------------------------------------------------- 1 | package istio 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 7 | ) 8 | 9 | var ( 10 | log = logd.Get().WithName("dynakube-istio") 11 | ) 12 | 13 | const ( 14 | OperatorComponent = "operator" 15 | OneAgentComponent = "oneagent" 16 | CodeModuleComponent = "CodeModule" 17 | ActiveGateComponent = "ActiveGate" 18 | IstioGVRName = "networking.istio.io" 19 | IstioGVRVersion = "v1beta1" 20 | ) 21 | 22 | var ( 23 | IstioGVR = fmt.Sprintf("%s/%s", IstioGVRName, IstioGVRVersion) 24 | ) 25 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/extensions_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta5/dynakube/extensions" 5 | ) 6 | 7 | func (dk *DynaKube) Extensions() *extensions.Extensions { 8 | ext := &extensions.Extensions{ 9 | ExecutionControllerSpec: &dk.Spec.Templates.ExtensionExecutionController, 10 | } 11 | // Set required fields for getters that may be called when extensions are disabled. 12 | ext.SetName(dk.Name) 13 | ext.SetNamespace(dk.Namespace) 14 | ext.SetEnabled(dk.Spec.Extensions != nil) 15 | 16 | return ext 17 | } 18 | -------------------------------------------------------------------------------- /pkg/util/conditions/token.go: -------------------------------------------------------------------------------- 1 | package conditions 2 | 3 | import ( 4 | "k8s.io/apimachinery/pkg/api/meta" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | const ( 9 | DataIngestTokenMissing = "DataIngestTokenMissing" 10 | ) 11 | 12 | func SetDataIngestTokenMissing(conditions *[]metav1.Condition, conditionType string, msg string) { 13 | condition := metav1.Condition{ 14 | Type: conditionType, 15 | Status: metav1.ConditionFalse, 16 | Reason: DataIngestTokenMissing, 17 | Message: msg, 18 | } 19 | _ = meta.SetStatusCondition(conditions, condition) 20 | } 21 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | See the License for the specific language governing permissions and 12 | limitations under the License. 13 | */ -------------------------------------------------------------------------------- /pkg/api/validation/edgeconnect/host_patterns.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1alpha2/edgeconnect" 7 | ) 8 | 9 | const ( 10 | errorHostPattersIsRequired = `hostPatterns is required when using provisioner mode` 11 | ) 12 | 13 | func checkHostPatternsValue(_ context.Context, _ *Validator, ec *edgeconnect.EdgeConnect) string { 14 | if ec.IsProvisionerModeEnabled() && len(ec.Spec.HostPatterns) == 0 && !ec.IsK8SAutomationEnabled() { 15 | return errorHostPattersIsRequired 16 | } 17 | 18 | return "" 19 | } 20 | -------------------------------------------------------------------------------- /cmd/supportarchive/logger_test.go: -------------------------------------------------------------------------------- 1 | package supportarchive 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestSupportArchiveLogger(t *testing.T) { 11 | logBuffer := bytes.Buffer{} 12 | logger := newSupportArchiveLogger(&logBuffer) 13 | 14 | logger.Info("info message") 15 | logger.Error(assert.AnError, "error message") 16 | 17 | logLines := logBuffer.String() 18 | 19 | assert.Contains(t, logLines, "info message") 20 | assert.Contains(t, logLines, "error message") 21 | assert.Contains(t, logLines, supportArchiveLoggerName) 22 | } 23 | -------------------------------------------------------------------------------- /pkg/api/validation/edgeconnect/webhook.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | v1alpha1 "github.com/Dynatrace/dynatrace-operator/pkg/api/v1alpha1/edgeconnect" 5 | v1alpha2 "github.com/Dynatrace/dynatrace-operator/pkg/api/v1alpha2/edgeconnect" 6 | ctrl "sigs.k8s.io/controller-runtime" 7 | ) 8 | 9 | func SetupWebhookWithManager(mgr ctrl.Manager) error { 10 | validator := New(mgr.GetAPIReader(), mgr.GetConfig()) 11 | 12 | if err := v1alpha1.SetupWebhookWithManager(mgr, validator); err != nil { 13 | return err 14 | } 15 | 16 | return v1alpha2.SetupWebhookWithManager(mgr, validator) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/util/prioritymap/cmdline_parser.go: -------------------------------------------------------------------------------- 1 | package prioritymap 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | const DefaultSeparator = "=" 8 | 9 | // ParseCommandLineArgument splits strings in the format of "--param=value" up in its components "--param", "=" and "value". 10 | // The separator is returned to let the caller know if it was there 11 | func ParseCommandLineArgument(arg string) (string, string, string) { 12 | arg, value, foundSeparator := strings.Cut(arg, DefaultSeparator) 13 | 14 | if foundSeparator { 15 | return arg, DefaultSeparator, value 16 | } 17 | 18 | return arg, "", "" 19 | } 20 | -------------------------------------------------------------------------------- /config/helm/chart/default/templates/Common/webhook/poddisruptionbudget-webhook.yaml: -------------------------------------------------------------------------------- 1 | {{- if (.Values.webhook).highAvailability }} 2 | # v1 version supported since k8s 1.21 3 | apiVersion: {{ .Capabilities.APIVersions.Has "policy/v1" | ternary "policy/v1" "policy/v1beta1" }} 4 | kind: PodDisruptionBudget 5 | metadata: 6 | name: dynatrace-webhook 7 | namespace: {{ .Release.Namespace }} 8 | labels: 9 | {{- include "dynatrace-operator.webhookLabels" . | nindent 4 }} 10 | spec: 11 | minAvailable: 1 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/component: webhook 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/activegate_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta3/dynakube/activegate" 5 | ) 6 | 7 | func (dk *DynaKube) ActiveGate() *activegate.ActiveGate { 8 | dk.Spec.ActiveGate.SetApiUrl(dk.ApiUrl()) 9 | dk.Spec.ActiveGate.SetName(dk.Name) 10 | dk.Spec.ActiveGate.SetAutomaticTLSCertificate(dk.FF().IsActiveGateAutomaticTLSCertificate()) 11 | dk.Spec.ActiveGate.SetExtensionsDependency(dk.IsExtensionsEnabled()) 12 | 13 | return &activegate.ActiveGate{ 14 | Spec: &dk.Spec.ActiveGate, 15 | Status: &dk.Status.ActiveGate, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/activegate_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta4/dynakube/activegate" 5 | ) 6 | 7 | func (dk *DynaKube) ActiveGate() *activegate.ActiveGate { 8 | dk.Spec.ActiveGate.SetAPIURL(dk.APIURL()) 9 | dk.Spec.ActiveGate.SetName(dk.Name) 10 | dk.Spec.ActiveGate.SetAutomaticTLSCertificate(dk.FF().IsActiveGateAutomaticTLSCertificate()) 11 | dk.Spec.ActiveGate.SetExtensionsDependency(dk.IsExtensionsEnabled()) 12 | 13 | return &activegate.ActiveGate{ 14 | Spec: &dk.Spec.ActiveGate, 15 | Status: &dk.Status.ActiveGate, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/activegate_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/activegate" 5 | ) 6 | 7 | func (dk *DynaKube) ActiveGate() *activegate.ActiveGate { 8 | dk.Spec.ActiveGate.SetAPIURL(dk.APIURL()) 9 | dk.Spec.ActiveGate.SetName(dk.Name) 10 | dk.Spec.ActiveGate.SetAutomaticTLSCertificate(dk.FF().IsActiveGateAutomaticTLSCertificate()) 11 | dk.Spec.ActiveGate.SetExtensionsDependency(dk.Extensions().IsAnyEnabled()) 12 | 13 | return &activegate.ActiveGate{ 14 | Spec: &dk.Spec.ActiveGate, 15 | Status: &dk.Status.ActiveGate, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/activegate_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta5/dynakube/activegate" 5 | ) 6 | 7 | func (dk *DynaKube) ActiveGate() *activegate.ActiveGate { 8 | dk.Spec.ActiveGate.SetAPIURL(dk.APIURL()) 9 | dk.Spec.ActiveGate.SetName(dk.Name) 10 | dk.Spec.ActiveGate.SetAutomaticTLSCertificate(dk.FF().IsActiveGateAutomaticTLSCertificate()) 11 | dk.Spec.ActiveGate.SetExtensionsDependency(dk.Extensions().IsEnabled()) 12 | 13 | return &activegate.ActiveGate{ 14 | Spec: &dk.Spec.ActiveGate, 15 | Status: &dk.Status.ActiveGate, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkg/clients/utils/http_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | func TestCloseBodyAfterRequest(t *testing.T) { 11 | type args struct { 12 | response *http.Response 13 | } 14 | 15 | tests := []struct { 16 | name string 17 | args args 18 | }{ 19 | {`nil http.Response`, args{response: nil}}, 20 | {`nil http.Response`, args{response: &http.Response{Body: io.NopCloser(strings.NewReader(""))}}}, 21 | } 22 | for _, tt := range tests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | CloseBodyAfterRequest(tt.args.response) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/mutator/metadata/deprecated.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | import podattr "github.com/Dynatrace/dynatrace-bootstrapper/cmd/configure/attributes/pod" 4 | 5 | const ( 6 | DeprecatedWorkloadKindKey = "dt.kubernetes.workload.kind" 7 | DeprecatedWorkloadNameKey = "dt.kubernetes.workload.name" 8 | ) 9 | 10 | func SetDeprecatedAttributes(attrs *podattr.Attributes) { 11 | if attrs.UserDefined == nil { 12 | attrs.UserDefined = map[string]string{} 13 | } 14 | 15 | attrs.UserDefined[DeprecatedWorkloadKindKey] = attrs.WorkloadKind 16 | attrs.UserDefined[DeprecatedWorkloadNameKey] = attrs.WorkloadName 17 | } 18 | -------------------------------------------------------------------------------- /pkg/util/conditions/suffix.go: -------------------------------------------------------------------------------- 1 | package conditions 2 | 3 | import "fmt" 4 | 5 | const ( 6 | createdSuffix = "created" 7 | updatedSuffix = "updated" 8 | createdOrUpdatedSuffix = "created/updated" 9 | outdatedSuffix = "outdated" 10 | ) 11 | 12 | func appendCreatedSuffix(name string) string { 13 | return fmt.Sprintf("%s %s", name, createdSuffix) 14 | } 15 | 16 | func appendCreatedOrUpdatedSuffix(name string) string { 17 | return fmt.Sprintf("%s %s", name, createdOrUpdatedSuffix) 18 | } 19 | 20 | func appendOutdatedSuffix(name string) string { 21 | return fmt.Sprintf("%s %s", name, outdatedSuffix) 22 | } 23 | -------------------------------------------------------------------------------- /pkg/api/shared/communication/types.go: -------------------------------------------------------------------------------- 1 | package communication 2 | 3 | import ( 4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 5 | ) 6 | 7 | // +kubebuilder:object:generate=true 8 | 9 | type ConnectionInfo struct { 10 | 11 | // Time of the last connection request 12 | LastRequest metav1.Time `json:"lastRequest,omitempty"` 13 | // UUID of the tenant, received from the tenant 14 | TenantUUID string `json:"tenantUUID,omitempty"` 15 | 16 | // Available connection endpoints 17 | Endpoints string `json:"endpoints,omitempty"` 18 | 19 | // Hash of the tenant token 20 | TenantTokenHash string `json:"tenantTokenHash,omitempty"` 21 | } 22 | -------------------------------------------------------------------------------- /assets/calico/agent-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: allow-agent-traffic 5 | spec: 6 | podSelector: 7 | matchLabels: 8 | app: myapp 9 | policyTypes: 10 | - Egress 11 | egress: 12 | # Allow DNS lookup 13 | - to: 14 | - namespaceSelector: 15 | matchLabels: 16 | kubernetes.io/metadata.name: kube-system 17 | ports: 18 | - protocol: UDP 19 | port: 53 20 | - protocol: TCP 21 | port: 53 22 | # Allow external traffic for e.g. Cluster API requests 23 | - to: 24 | - ipBlock: 25 | cidr: 0.0.0.0/0 26 | ports: [] 27 | -------------------------------------------------------------------------------- /pkg/otelcgen/processors_test.go: -------------------------------------------------------------------------------- 1 | package otelcgen 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestNewConfigWithProcessors(t *testing.T) { 13 | cfg, err := NewConfig( 14 | "", 15 | RegisteredProtocols, 16 | WithProcessors(), 17 | ) 18 | require.NoError(t, err) 19 | c, err := cfg.Marshal() 20 | require.NoError(t, err) 21 | 22 | expectedOutput, err := os.ReadFile(filepath.Join("testdata", "processors_only.yaml")) 23 | require.NoError(t, err) 24 | 25 | assert.YAMLEq(t, string(expectedOutput), string(c)) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/util/kubernetes/objects/k8sevent/event.go: -------------------------------------------------------------------------------- 1 | package k8sevent 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | "k8s.io/client-go/tools/record" 6 | "sigs.k8s.io/controller-runtime/pkg/client" 7 | ) 8 | 9 | const ( 10 | crdVersionMismatchReason = "CRDVersionMismatch" 11 | crdVersionMismatchMessage = "The CustomResourceDefinition doesn't match version with the operator. Please update the CRD to avoid potential issues." 12 | ) 13 | 14 | func SendCRDVersionMismatch(eventRecorder record.EventRecorder, object client.Object) { 15 | eventRecorder.Event(object, corev1.EventTypeWarning, crdVersionMismatchReason, crdVersionMismatchMessage) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/otelcgen/extensions_test.go: -------------------------------------------------------------------------------- 1 | package otelcgen 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestNewConfigWithExtensions(t *testing.T) { 13 | cfg, err := NewConfig( 14 | "test", 15 | RegisteredProtocols, 16 | WithExtensions(), 17 | ) 18 | require.NoError(t, err) 19 | c, err := cfg.Marshal() 20 | require.NoError(t, err) 21 | 22 | expectedOutput, err := os.ReadFile(filepath.Join("testdata", "extensions_only.yaml")) 23 | require.NoError(t, err) 24 | 25 | assert.YAMLEq(t, string(expectedOutput), string(c)) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/otelcgen/testdata/receivers_otlp_only.yaml: -------------------------------------------------------------------------------- 1 | connectors: {} 2 | exporters: {} 3 | extensions: {} 4 | processors: {} 5 | receivers: 6 | otlp: 7 | protocols: 8 | grpc: 9 | endpoint: test:4317 10 | tls: 11 | cert_file: /run/opensignals/tls/tls.crt 12 | key_file: /run/opensignals/tls/tls.key 13 | http: 14 | endpoint: test:4318 15 | tls: 16 | cert_file: /run/opensignals/tls/tls.crt 17 | key_file: /run/opensignals/tls/tls.key 18 | service: 19 | extensions: [] 20 | pipelines: {} 21 | -------------------------------------------------------------------------------- /test/project/project.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package project 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | var rootDir string 11 | 12 | func RootDir() string { 13 | return rootDir 14 | } 15 | 16 | func TestDataDir() string { 17 | return filepath.Join(rootDir, "test", "testdata") 18 | } 19 | 20 | func init() { 21 | rootDir = "." 22 | 23 | dir, err := os.Getwd() 24 | if err != nil { 25 | return 26 | } 27 | 28 | for dir != "" { 29 | goModPath := filepath.Join(dir, "go.mod") 30 | if _, err := os.Stat(goModPath); err == nil { 31 | rootDir = dir 32 | 33 | return 34 | } 35 | 36 | dir = filepath.Dir(dir) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkg/util/eventfilter/eventfilter.go: -------------------------------------------------------------------------------- 1 | package eventfilter 2 | 3 | import ( 4 | "sigs.k8s.io/controller-runtime/pkg/client" 5 | "sigs.k8s.io/controller-runtime/pkg/predicate" 6 | ) 7 | 8 | func ForObjectNameAndNamespace(name string, namespace string) predicate.Predicate { 9 | return predicate.NewPredicateFuncs(func(object client.Object) bool { 10 | return isInNamespace(object, namespace) && hasName(object, name) 11 | }) 12 | } 13 | 14 | func hasName(object client.Object, name string) bool { 15 | return object.GetName() == name 16 | } 17 | 18 | func isInNamespace(object client.Object, namespace string) bool { 19 | return object.GetNamespace() == namespace 20 | } 21 | -------------------------------------------------------------------------------- /config/helm/chart/default/tests/Common/edgeconnect/serviceaccount-edgeconnect_test.yaml: -------------------------------------------------------------------------------- 1 | suite: test serviceaccount for edgeconnect 2 | templates: 3 | - Common/edge-connect/serviceaccount-edgeconnect.yaml 4 | tests: 5 | - it: should exist 6 | set: 7 | rbac.edgeConnect.annotations: 8 | test: test 9 | asserts: 10 | - isKind: 11 | of: ServiceAccount 12 | - equal: 13 | path: metadata.annotations 14 | value: 15 | test: test 16 | - it: shouldn't exist if turned off 17 | set: 18 | rbac.edgeConnect.create: false 19 | asserts: 20 | - hasDocuments: 21 | count: 0 22 | -------------------------------------------------------------------------------- /pkg/api/validation/dynakube/preview_test.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 7 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/oneagent" 8 | ) 9 | 10 | func TestPreviewWarning(t *testing.T) { 11 | t.Run("no warning", func(t *testing.T) { 12 | assertAllowedWithoutWarnings(t, &dynakube.DynaKube{ 13 | ObjectMeta: defaultDynakubeObjectMeta, 14 | Spec: dynakube.DynaKubeSpec{ 15 | APIURL: testAPIURL, 16 | OneAgent: oneagent.Spec{ 17 | ApplicationMonitoring: &oneagent.ApplicationMonitoringSpec{}, 18 | }, 19 | }, 20 | }) 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /config/helm/chart/default/tests/Common/operator/allowlistsynchronizer_test.yaml: -------------------------------------------------------------------------------- 1 | suite: test allowlistsynchronizer for GKE-Autopilot 2 | templates: 3 | - Common/operator/allowlistsynchronizer.yaml 4 | tests: 5 | - it: shouldn't exist by default 6 | asserts: 7 | - hasDocuments: 8 | count: 0 9 | - it: should exist on GKE-Autopilot 10 | capabilities: 11 | apiVersions: 12 | - auto.gke.io/v1/AllowlistSynchronizer 13 | asserts: 14 | - isKind: 15 | of: AllowlistSynchronizer 16 | - isAPIVersion: 17 | of: auto.gke.io/v1 18 | - equal: 19 | path: metadata.name 20 | value: dynatrace-operator 21 | -------------------------------------------------------------------------------- /pkg/clients/dynatrace/activegate_version.go: -------------------------------------------------------------------------------- 1 | package dynatrace 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | // GetLatestActiveGateVersion gets the latest gateway version for the given OS and arch configured on the Tenant. 10 | func (dtc *dynatraceClient) GetLatestActiveGateVersion(ctx context.Context, os string) (string, error) { 11 | response := struct { 12 | LatestGatewayVersion string `json:"latestGatewayVersion"` 13 | }{} 14 | 15 | url := dtc.getLatestActiveGateVersionURL(os) 16 | err := dtc.makeRequestAndUnmarshal(ctx, url, dynatracePaaSToken, &response) 17 | 18 | return response.LatestGatewayVersion, errors.WithStack(err) 19 | } 20 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/oneagent/daemonset/affinity.go: -------------------------------------------------------------------------------- 1 | package daemonset 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/status" 5 | "github.com/Dynatrace/dynatrace-operator/pkg/util/kubernetes/fields/k8saffinity" 6 | corev1 "k8s.io/api/core/v1" 7 | ) 8 | 9 | func (b *builder) affinity() *corev1.Affinity { 10 | var affinity corev1.Affinity 11 | if b.dk.Status.OneAgent.Source == status.TenantRegistryVersionSource || b.dk.Status.OneAgent.Source == status.CustomVersionVersionSource { 12 | affinity = k8saffinity.NewAMDOnlyNodeAffinity() 13 | } else { 14 | affinity = k8saffinity.NewMultiArchNodeAffinity() 15 | } 16 | 17 | return &affinity 18 | } 19 | -------------------------------------------------------------------------------- /pkg/otelcgen/testdata/receivers_statsd.yaml: -------------------------------------------------------------------------------- 1 | connectors: {} 2 | exporters: {} 3 | extensions: {} 4 | processors: {} 5 | receivers: 6 | statsd: 7 | endpoint: test:8125 8 | timer_histogram_mapping: 9 | - histogram: 10 | max_size: 10 11 | observer_type: histogram 12 | statsd_type: histogram 13 | - histogram: 14 | max_size: 100 15 | observer_type: histogram 16 | statsd_type: timing 17 | - histogram: 18 | max_size: 100 19 | observer_type: histogram 20 | statsd_type: distribution 21 | service: 22 | extensions: [] 23 | pipelines: {} 24 | -------------------------------------------------------------------------------- /test/helpers/kubeobjects/manifests/decode.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package manifests 4 | 5 | import ( 6 | "os" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | "sigs.k8s.io/controller-runtime/pkg/client" 11 | "sigs.k8s.io/e2e-framework/klient/decoder" 12 | ) 13 | 14 | func ObjectFromFile[T client.Object](t *testing.T, path string) T { 15 | kubernetesManifest, err := os.Open(path) 16 | defer func() { require.NoError(t, kubernetesManifest.Close()) }() 17 | require.NoError(t, err) 18 | 19 | rawObject, err := decoder.DecodeAny(kubernetesManifest) 20 | require.NoError(t, err) 21 | 22 | object, ok := rawObject.(T) 23 | require.True(t, ok) 24 | 25 | return object 26 | } 27 | -------------------------------------------------------------------------------- /config/helm/chart/default/tests/Google/application_test.yaml: -------------------------------------------------------------------------------- 1 | suite: tests google application custom resource 2 | templates: 3 | - application.yaml 4 | tests: 5 | - it: should not exist if platform is set to kubernetes 6 | set: 7 | platform: kubernetes 8 | asserts: 9 | - hasDocuments: 10 | count: 0 11 | 12 | - it: should not exist if platform is set to openshift 13 | set: 14 | platform: openshift 15 | asserts: 16 | - hasDocuments: 17 | count: 0 18 | 19 | - it: should exist if platform is set to google-marketplace 20 | set: 21 | platform: google-marketplace 22 | asserts: 23 | - hasDocuments: 24 | count: 1 25 | -------------------------------------------------------------------------------- /pkg/controllers/csi/driver/config.go: -------------------------------------------------------------------------------- 1 | package csidriver 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 7 | "github.com/prometheus/client_golang/prometheus" 8 | "sigs.k8s.io/controller-runtime/pkg/metrics" 9 | ) 10 | 11 | var ( 12 | log = logd.Get().WithName("csi-driver") 13 | memoryUsageMetric = prometheus.NewGauge(prometheus.GaugeOpts{ 14 | Namespace: "dynatrace", 15 | Subsystem: "csi_driver", 16 | Name: "memory_usage", 17 | Help: "Memory usage of the csi driver in bytes", 18 | }) 19 | memoryMetricTick = 5000 * time.Millisecond 20 | ) 21 | 22 | func init() { 23 | metrics.Registry.MustRegister(memoryUsageMetric) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/authtoken/conditions.go: -------------------------------------------------------------------------------- 1 | package authtoken 2 | 3 | import ( 4 | cond "github.com/Dynatrace/dynatrace-operator/pkg/util/conditions" 5 | "k8s.io/apimachinery/pkg/api/meta" 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | ) 8 | 9 | const ActiveGateAuthTokenSecretConditionType string = "ActiveGateAuthTokenSecret" 10 | 11 | func setAuthSecretCreated(conditions *[]metav1.Condition, conditionType string, msg string) { 12 | condition := metav1.Condition{ 13 | Type: conditionType, 14 | Status: metav1.ConditionTrue, 15 | Reason: cond.SecretCreatedReason, 16 | Message: msg, 17 | } 18 | _ = meta.SetStatusCondition(conditions, condition) 19 | } 20 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/mutator/container.go: -------------------------------------------------------------------------------- 1 | package mutator 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func checkInjectionAnnotation(annotations map[string]string, name string) bool { 8 | for key, value := range annotations { 9 | if strings.HasPrefix(key, AnnotationContainerInjection) { 10 | _, path, hasPath := strings.Cut(key, "/") 11 | if hasPath && path == name { 12 | return value == "false" 13 | } 14 | } 15 | } 16 | 17 | return false 18 | } 19 | 20 | func IsContainerExcludedFromInjection(dkAnnotations, podAnnotations map[string]string, name string) bool { 21 | return checkInjectionAnnotation(dkAnnotations, name) || checkInjectionAnnotation(podAnnotations, name) 22 | } 23 | -------------------------------------------------------------------------------- /cmd/supportarchive/config.go: -------------------------------------------------------------------------------- 1 | package supportarchive 2 | 3 | const OperatorVersionFileName = "operator-version.txt" 4 | const SupportArchiveOutputFileName = "supportarchive_console.log" 5 | 6 | const LogsDirectoryName = "logs" 7 | const ManifestsDirectoryName = "manifests" 8 | const InjectedNamespacesManifestsDirectoryName = "injected_namespaces" 9 | const CRDDirectoryName = "crds" 10 | const WebhookConfigurationsDirectoryName = "webhook_configurations" 11 | const ManifestsFileExtension = ".yaml" 12 | 13 | const CRDKindName = "CustomResourceDefinition" 14 | const ValidatingWebhookConfigurationKind = "ValidatingWebhookConfiguration" 15 | const MutatingWebhookConfigurationKind = "MutatingWebhookConfiguration" 16 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/metadataenrichment/props.go: -------------------------------------------------------------------------------- 1 | package metadataenrichment 2 | 3 | import ( 4 | "strings" 5 | 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | ) 8 | 9 | func (r Rule) ToAnnotationKey() string { 10 | if r.Target == "" { 11 | return "" 12 | } 13 | 14 | return Prefix + r.Target 15 | } 16 | 17 | func GetEmptyTargetEnrichmentKey(metadataType, key string) string { 18 | return namespaceKeyPrefix + strings.ToLower(metadataType) + "." + key 19 | } 20 | 21 | func (m *MetadataEnrichment) IsEnabled() bool { 22 | return m.Enabled != nil && *m.Enabled 23 | } 24 | 25 | func (m *MetadataEnrichment) GetNamespaceSelector() *metav1.LabelSelector { 26 | return &m.NamespaceSelector 27 | } 28 | -------------------------------------------------------------------------------- /pkg/util/kubernetes/fields/k8svolume/volumes.go: -------------------------------------------------------------------------------- 1 | package k8svolume 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | corev1 "k8s.io/api/core/v1" 6 | ) 7 | 8 | func Contains(vol []corev1.Volume, volumeName string) bool { 9 | for _, v := range vol { 10 | if v.Name == volumeName { 11 | return true 12 | } 13 | } 14 | 15 | return false 16 | } 17 | 18 | func FindByName(volumes []corev1.Volume, volumeName string) (*corev1.Volume, error) { 19 | for _, volume := range volumes { 20 | if volume.Name == volumeName { 21 | return &volume, nil 22 | } 23 | } 24 | 25 | return nil, errors.Errorf(`Cannot find volume "%s" in the provided slice (len %d)`, 26 | volumeName, len(volumes), 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/kspm/props.go: -------------------------------------------------------------------------------- 1 | package kspm 2 | 3 | import ( 4 | "slices" 5 | ) 6 | 7 | func (kspm *Kspm) SetName(name string) { 8 | kspm.name = name 9 | } 10 | 11 | func (kspm *Kspm) IsEnabled() bool { 12 | return kspm.Spec != nil 13 | } 14 | 15 | func (kspm *Kspm) GetTokenSecretName() string { 16 | return kspm.name + "-" + TokenSecretKey 17 | } 18 | 19 | func (kspm *Kspm) GetDaemonSetName() string { 20 | return kspm.name + "-" + NodeCollectorNameSuffix 21 | } 22 | 23 | func (kspm *Kspm) GetUniqueMappedHostPaths() []string { 24 | tmpMappedHostPaths := append([]string{}, kspm.MappedHostPaths...) 25 | slices.Sort(tmpMappedHostPaths) 26 | 27 | return slices.Compact(tmpMappedHostPaths) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/kspm/props.go: -------------------------------------------------------------------------------- 1 | package kspm 2 | 3 | import ( 4 | "slices" 5 | ) 6 | 7 | func (kspm *Kspm) SetName(name string) { 8 | kspm.name = name 9 | } 10 | 11 | func (kspm *Kspm) IsEnabled() bool { 12 | return kspm.Spec != nil 13 | } 14 | 15 | func (kspm *Kspm) GetTokenSecretName() string { 16 | return kspm.name + "-" + TokenSecretKey 17 | } 18 | 19 | func (kspm *Kspm) GetDaemonSetName() string { 20 | return kspm.name + "-" + NodeCollectorNameSuffix 21 | } 22 | 23 | func (kspm *Kspm) GetUniqueMappedHostPaths() []string { 24 | tmpMappedHostPaths := append([]string{}, kspm.MappedHostPaths...) 25 | slices.Sort(tmpMappedHostPaths) 26 | 27 | return slices.Compact(tmpMappedHostPaths) 28 | } 29 | -------------------------------------------------------------------------------- /hack/build/create_go_linker_args.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$2" ] 4 | then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | version=$1 10 | commit=$2 11 | debug=${3:-false} 12 | 13 | build_date="$(date -u +"%Y-%m-%dT%H:%M:%S+00:00")" 14 | go_linker_args=( 15 | "-X 'github.com/Dynatrace/dynatrace-operator/pkg/version.Version=${version}'" 16 | "-X 'github.com/Dynatrace/dynatrace-operator/pkg/version.Commit=${commit}'" 17 | "-X 'github.com/Dynatrace/dynatrace-operator/pkg/version.BuildDate=${build_date}'" 18 | "-extldflags=-static" 19 | ) 20 | 21 | if [ "$debug" != true ]; then 22 | go_linker_args+=("-s -w") 23 | fi 24 | 25 | echo "${go_linker_args[*]}" 26 | -------------------------------------------------------------------------------- /pkg/arch/consts.go: -------------------------------------------------------------------------------- 1 | package arch 2 | 3 | import containerv1 "github.com/google/go-containerregistry/pkg/v1" 4 | 5 | const ( 6 | FlavorDefault = "default" 7 | FlavorMultidistro = "multidistro" 8 | 9 | // These architectures are for the DynatraceAPI 10 | 11 | ArchX86 = "x86" 12 | ArchARM = "arm" 13 | ArchPPCLE = "ppcle" 14 | ArchS390 = "s390" 15 | 16 | // These architectures are for the Image Registry 17 | 18 | AMDImage = "amd64" 19 | ARMImage = "arm64" 20 | PPCLEImage = "ppc64le" 21 | S390Image = "s390x" 22 | 23 | DefaultImageOS = "linux" 24 | ) 25 | 26 | var ( 27 | ImagePlatform = containerv1.Platform{ 28 | OS: DefaultImageOS, 29 | Architecture: ImageArch, 30 | } 31 | ) 32 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/activegate/internal/statefulset/builder/modifiers/authtoken_test.go: -------------------------------------------------------------------------------- 1 | package modifiers 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestAuthTokenModify(t *testing.T) { 10 | t.Run("successfully modified", func(t *testing.T) { 11 | dk := getBaseDynakube() 12 | enableKubeMonCapability(&dk) 13 | mod := NewAuthTokenModifier(dk) 14 | builder := createBuilderForTesting() 15 | 16 | sts, _ := builder.AddModifier(mod).Build() 17 | 18 | require.NotEmpty(t, sts) 19 | isSubset(t, mod.getVolumes(), sts.Spec.Template.Spec.Volumes) 20 | isSubset(t, mod.getVolumeMounts(), sts.Spec.Template.Spec.Containers[0].VolumeMounts) 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/extensions_props.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/extensions" 5 | ) 6 | 7 | func (dk *DynaKube) Extensions() *extensions.Extensions { 8 | ext := &extensions.Extensions{ 9 | ExecutionController: &dk.Spec.Templates.ExtensionExecutionController, 10 | } 11 | if dk.Spec.Extensions != nil { 12 | ext.Databases = dk.Spec.Extensions.Databases 13 | } 14 | 15 | // Set required fields for getters that may be called when extensions are disabled. 16 | ext.SetName(dk.Name) 17 | ext.SetNamespace(dk.Namespace) 18 | ext.SetPrometheusEnabled(dk.Spec.Extensions != nil && dk.Spec.Extensions.Prometheus != nil) 19 | 20 | return ext 21 | } 22 | -------------------------------------------------------------------------------- /pkg/controllers/csi/driver/volumes/app/config.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | "github.com/prometheus/client_golang/prometheus" 6 | "sigs.k8s.io/controller-runtime/pkg/metrics" 7 | ) 8 | 9 | var ( 10 | log = logd.Get().WithName("csi-appvolume") 11 | agentsVersionsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{ 12 | Namespace: "dynatrace", 13 | Subsystem: "csi_driver", 14 | Name: "agent_versions", 15 | Help: "Number of an agent version currently mounted by the CSI driver", 16 | }, []string{"version"}) 17 | ) 18 | 19 | const Mode = "app" 20 | 21 | func init() { 22 | metrics.Registry.MustRegister(agentsVersionsMetric) 23 | } 24 | -------------------------------------------------------------------------------- /pkg/util/oneagentapm/oneagentapm.go: -------------------------------------------------------------------------------- 1 | package oneagentapm 2 | 3 | import ( 4 | "k8s.io/client-go/discovery" 5 | "k8s.io/client-go/rest" 6 | ) 7 | 8 | // Exists checks if a OneAgentAPM object exists 9 | func Exists(cfg *rest.Config) (bool, error) { 10 | client, err := discovery.NewDiscoveryClientForConfig(cfg) 11 | if err != nil { 12 | return false, err 13 | } 14 | 15 | _, resourceList, err := client.ServerGroupsAndResources() 16 | if err != nil { 17 | return false, err 18 | } 19 | 20 | for _, resource := range resourceList { 21 | for _, apiResource := range resource.APIResources { 22 | if apiResource.Kind == "OneAgentAPM" { 23 | return true, nil 24 | } 25 | } 26 | } 27 | 28 | return false, nil 29 | } 30 | -------------------------------------------------------------------------------- /pkg/api/validation/edgeconnect/automation_validation.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1alpha2/edgeconnect" 7 | ) 8 | 9 | const ( 10 | errorAutomationRequiresProvisioner = `When enabling Kubernetes automation using provisioner mode is mandatory! Please enable spec.oauth.provisioner and provide a resp. OAuth client configuration.` 11 | ) 12 | 13 | func automationRequiresProvisionerValidation(_ context.Context, _ *Validator, ec *edgeconnect.EdgeConnect) string { 14 | if ec.Spec.KubernetesAutomation != nil && ec.Spec.KubernetesAutomation.Enabled && !ec.Spec.OAuth.Provisioner { 15 | return errorAutomationRequiresProvisioner 16 | } 17 | 18 | return "" 19 | } 20 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/zip/config.go: -------------------------------------------------------------------------------- 1 | package zip 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/injection/codemodule/installer/common" 7 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 8 | ) 9 | 10 | var ( 11 | log = logd.Get().WithName("oneagent-zip") 12 | ) 13 | 14 | // Checks if a file is under /agent/conf 15 | // Different archive file implementations return different output, this function handles the differences 16 | // tar.Header.Name == "./path/to/file" 17 | // zip.File.Name == "path/to/file" 18 | func isAgentConfFile(fileName string) bool { 19 | return strings.HasPrefix(fileName, "./"+common.AgentConfDirPath) || strings.HasPrefix(fileName, common.AgentConfDirPath) 20 | } 21 | -------------------------------------------------------------------------------- /test/testdata/network/proxy-scc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.openshift.io/v1 2 | kind: SecurityContextConstraints 3 | metadata: 4 | name: proxy 5 | runAsUser: 6 | type: RunAsAny 7 | seLinuxContext: 8 | type: RunAsAny 9 | fsGroup: 10 | type: RunAsAny 11 | supplementalGroups: 12 | type: RunAsAny 13 | allowHostDirVolumePlugin: true 14 | allowHostIPC: true 15 | allowHostNetwork: true 16 | allowHostPID: true 17 | allowHostPorts: true 18 | allowPrivilegeEscalation: true 19 | allowPrivilegedContainer: true 20 | allowedCapabilities: 21 | - "*" 22 | allowedUnsafeSysctls: 23 | - "*" 24 | priority: 1 25 | readOnlyRootFilesystem: false 26 | requiredDropCapabilities: [] 27 | users: 28 | - system:serviceaccount:proxy:proxy 29 | volumes: 30 | - "*" 31 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/connectioninfo/oneagent/conditions.go: -------------------------------------------------------------------------------- 1 | package oaconnectioninfo 2 | 3 | import ( 4 | "k8s.io/apimachinery/pkg/api/meta" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | const ( 9 | oaConnectionInfoConditionType = "OneAgentConnectionInfo" 10 | 11 | EmptyCommunicationHostsReason = "EmptyCommunicationHosts" 12 | ) 13 | 14 | func setEmptyCommunicationHostsCondition(conditions *[]metav1.Condition) { 15 | condition := metav1.Condition{ 16 | Type: oaConnectionInfoConditionType, 17 | Status: metav1.ConditionFalse, 18 | Reason: EmptyCommunicationHostsReason, 19 | Message: "No communication hosts for OneAgent are available", 20 | } 21 | _ = meta.SetStatusCondition(conditions, condition) 22 | } 23 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/url/unpack.go: -------------------------------------------------------------------------------- 1 | package url 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | func (installer Installer) unpackOneAgentZip(targetDir string, tmpFile *os.File) error { 10 | var fileSize int64 11 | if stat, err := tmpFile.Stat(); err == nil { 12 | fileSize = stat.Size() 13 | } 14 | 15 | log.Info("saved OneAgent package", "dest", tmpFile.Name(), "size", fileSize) 16 | log.Info("unzipping OneAgent package") 17 | 18 | if err := installer.extractor.ExtractZip(tmpFile, targetDir); err != nil { 19 | log.Info("failed to unzip OneAgent package", "err", err) 20 | 21 | return errors.WithStack(err) 22 | } 23 | 24 | log.Info("unzipped OneAgent package") 25 | 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /pkg/util/map/map.go: -------------------------------------------------------------------------------- 1 | package maputil 2 | 3 | import ( 4 | "maps" 5 | "strconv" 6 | ) 7 | 8 | func GetField(values map[string]string, key string, defaultValue string) string { 9 | if x := values[key]; x != "" { 10 | return x 11 | } 12 | 13 | return defaultValue 14 | } 15 | 16 | func GetFieldBool(values map[string]string, key string, defaultValue bool) bool { 17 | if x := values[key]; x != "" { 18 | parsed, err := strconv.ParseBool(x) 19 | if err == nil { 20 | return parsed 21 | } 22 | } 23 | 24 | return defaultValue 25 | } 26 | 27 | func MergeMap(inputs ...map[string]string) map[string]string { 28 | res := map[string]string{} 29 | 30 | for _, m := range inputs { 31 | maps.Copy(res, m) 32 | } 33 | 34 | return res 35 | } 36 | -------------------------------------------------------------------------------- /config/helm/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Dynatrace LLC 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 | FROM gcr.io/cloud-marketplace-tools/k8s/deployer_helm/onbuild 16 | 17 | COPY schema.yaml /data-test/schema.yaml -------------------------------------------------------------------------------- /config/helm/chart/default/tests/Common/webhook/poddisruptionbudget-webhook_test.yaml: -------------------------------------------------------------------------------- 1 | suite: test PodDisruptionBudget 2 | templates: 3 | - Common/webhook/poddisruptionbudget-webhook.yaml 4 | tests: 5 | - it: should exist if highAvailability is set to true 6 | set: 7 | webhook.highAvailability: true 8 | asserts: 9 | - isKind: 10 | of: PodDisruptionBudget 11 | - equal: 12 | path: metadata.name 13 | value: dynatrace-webhook 14 | - equal: 15 | path: metadata.namespace 16 | value: NAMESPACE 17 | - it: shouldn't exist if highAvailability is set to false 18 | set: 19 | webhook.highAvailability: false 20 | asserts: 21 | - hasDocuments: 22 | count: 0 23 | -------------------------------------------------------------------------------- /pkg/api/shared/value/types.go: -------------------------------------------------------------------------------- 1 | package value 2 | 3 | // +kubebuilder:object:generate=true 4 | 5 | type Source struct { 6 | // Raw value for given property. 7 | // +nullable 8 | // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="property value",order=32,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced","urn:alm:descriptor:com.tectonic.ui:text"} 9 | Value string `json:"value,omitempty"` 10 | 11 | // Name of the secret to get the property from. 12 | // +nullable 13 | // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="property secret name",order=33,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced","urn:alm:descriptor:io.kubernetes:Secret"} 14 | ValueFrom string `json:"valueFrom,omitempty"` 15 | } 16 | -------------------------------------------------------------------------------- /pkg/api/shared/proxy/types.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | // +kubebuilder:object:generate=true 4 | 5 | type Spec struct { 6 | // Server address (hostname or IP address) of the proxy. 7 | Host string `json:"host,omitempty"` 8 | 9 | // NoProxy represents the NO_PROXY or no_proxy environment 10 | // variable. It specifies a string that contains comma-separated values 11 | // specifying hosts that should be excluded from proxying. 12 | NoProxy string `json:"noProxy,omitempty"` 13 | 14 | // Secret name which contains the username and password used for authentication with the proxy, using the 15 | // "Basic" HTTP authentication scheme. 16 | AuthRef string `json:"authRef,omitempty"` 17 | 18 | // Port of the proxy. 19 | Port uint32 `json:"port,omitempty"` 20 | } 21 | -------------------------------------------------------------------------------- /config/helm/chart/default/tests/Common/activegate/serviceaccount-activegate_test.yaml: -------------------------------------------------------------------------------- 1 | suite: test serviceaccount for activegate 2 | templates: 3 | - Common/activegate/serviceaccount-activegate.yaml 4 | tests: 5 | - it: should exist 6 | set: 7 | rbac.activeGate.annotations: 8 | test: test 9 | asserts: 10 | - isKind: 11 | of: ServiceAccount 12 | - equal: 13 | path: metadata.annotations 14 | value: 15 | test: test 16 | - equal: 17 | path: automountServiceAccountToken 18 | value: false 19 | - it: shouldn't exist if turned off 20 | set: 21 | rbac.activeGate.create: false 22 | asserts: 23 | - hasDocuments: 24 | count: 0 25 | -------------------------------------------------------------------------------- /pkg/otelcgen/exporters_test.go: -------------------------------------------------------------------------------- 1 | package otelcgen 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestNewConfigWithExporters(t *testing.T) { 13 | cfg, err := NewConfig( 14 | "", 15 | RegisteredProtocols, 16 | WithExportersEndpoint("test"), 17 | WithCA("/run/opensignals/cacerts/certs"), 18 | WithAPIToken("test-token"), 19 | WithExporters(), 20 | ) 21 | require.NoError(t, err) 22 | c, err := cfg.Marshal() 23 | require.NoError(t, err) 24 | 25 | expectedOutput, err := os.ReadFile(filepath.Join("testdata", "exporters_only.yaml")) 26 | require.NoError(t, err) 27 | 28 | assert.YAMLEq(t, string(expectedOutput), string(c)) 29 | } 30 | -------------------------------------------------------------------------------- /config/helm/README.md: -------------------------------------------------------------------------------- 1 | ## Tool Prerequisites 2 | 3 | * Install mpdev, see [google documentation](https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/blob/master/docs/tool-prerequisites.md) for more information 4 | * Create an empty GKE cluster 5 | * Apply Googles Application CRD, see [google documentation](https://github.com/GoogleCloudPlatform/marketplace-k8s-app-tools/blob/master/docs/tool-prerequisites.md) for more information 6 | 7 | ## Installation 8 | 9 | * Run `hack/gcr/deployer-image.sh` to build and push a new deployer image containing the helm charts 10 | * Run `hack/gcr/deploy.sh` to deploy the deployer image 11 | * In the Google Cloud Console, go to Kubernetes Clusters / Applications, select your cluster and check if the deployment was successful 12 | -------------------------------------------------------------------------------- /pkg/api/v1beta3/dynakube/metada_enrichment.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 4 | 5 | type MetadataEnrichment struct { 6 | // Enables MetadataEnrichment, `false` by default. 7 | // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="MetaDataEnrichment",xDescriptors="urn:alm:descriptor:com.tectonic.ui:selector:booleanSwitch" 8 | Enabled *bool `json:"enabled,omitempty"` 9 | 10 | // The namespaces where you want Dynatrace Operator to inject enrichment. 11 | // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Namespace Selector",xDescriptors="urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Namespace" 12 | NamespaceSelector metav1.LabelSelector `json:"namespaceSelector,omitempty"` 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/v1beta4/dynakube/metada_enrichment.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 4 | 5 | type MetadataEnrichment struct { 6 | // Enables MetadataEnrichment, `false` by default. 7 | // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="MetaDataEnrichment",xDescriptors="urn:alm:descriptor:com.tectonic.ui:selector:booleanSwitch" 8 | Enabled *bool `json:"enabled,omitempty"` 9 | 10 | // The namespaces where you want Dynatrace Operator to inject enrichment. 11 | // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Namespace Selector",xDescriptors="urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Namespace" 12 | NamespaceSelector metav1.LabelSelector `json:"namespaceSelector,omitempty"` 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/v1beta5/dynakube/metada_enrichment.go: -------------------------------------------------------------------------------- 1 | package dynakube 2 | 3 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 4 | 5 | type MetadataEnrichment struct { 6 | // Enables MetadataEnrichment, `false` by default. 7 | // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="MetaDataEnrichment",xDescriptors="urn:alm:descriptor:com.tectonic.ui:selector:booleanSwitch" 8 | Enabled *bool `json:"enabled,omitempty"` 9 | 10 | // The namespaces where you want Dynatrace Operator to inject enrichment. 11 | // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Namespace Selector",xDescriptors="urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Namespace" 12 | NamespaceSelector metav1.LabelSelector `json:"namespaceSelector,omitempty"` 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/validation/edgeconnect/module_test.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/Dynatrace/dynatrace-operator/pkg/util/installconfig" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestIsModuleDisabled(t *testing.T) { 12 | ctx := context.Background() 13 | 14 | t.Run("module disabled => error", func(t *testing.T) { 15 | errMsg := isModuleDisabled(ctx, &Validator{modules: installconfig.Modules{EdgeConnect: false}}, nil) 16 | assert.Equal(t, errorModuleDisabled, errMsg) 17 | }) 18 | 19 | t.Run("module enabled => no error", func(t *testing.T) { 20 | errMsg := isModuleDisabled(ctx, &Validator{modules: installconfig.Modules{EdgeConnect: true}}, nil) 21 | assert.Empty(t, errMsg) 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /cmd/troubleshoot/crd.go: -------------------------------------------------------------------------------- 1 | package troubleshoot 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | "github.com/pkg/errors" 6 | "k8s.io/apimachinery/pkg/runtime" 7 | ) 8 | 9 | func checkCRD(baseLog logd.Logger, err error) error { 10 | log := baseLog.WithName("crd") 11 | 12 | logNewCheckf(log, "checking if CRD for Dynakube exists ...") 13 | 14 | if err != nil { 15 | return DetermineDynakubeError(err) 16 | } 17 | 18 | logOkf(log, "CRD for Dynakube exists") 19 | 20 | return nil 21 | } 22 | 23 | func DetermineDynakubeError(err error) error { 24 | if runtime.IsNotRegisteredError(err) { 25 | err = errors.Wrap(err, "CRD for Dynakube missing") 26 | } else { 27 | err = errors.Wrap(err, "could not list Dynakube") 28 | } 29 | 30 | return err 31 | } 32 | -------------------------------------------------------------------------------- /pkg/util/kubernetes/objects/k8ssecret/tokens_test.go: -------------------------------------------------------------------------------- 1 | package k8ssecret 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/Dynatrace/dynatrace-operator/pkg/api/scheme/fake" 8 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 9 | "github.com/stretchr/testify/assert" 10 | "k8s.io/apimachinery/pkg/types" 11 | ) 12 | 13 | func TestGetDataFromSecretName(t *testing.T) { 14 | fakeClient := fake.NewClient() 15 | fakeClient.Create(context.Background(), getTestSecret()) 16 | ctx := context.Background() 17 | 18 | t.Run("get secret data", func(t *testing.T) { 19 | data, _ := GetDataFromSecretName(ctx, fakeClient, types.NamespacedName{Name: testSecretName, Namespace: testNamespace}, testSecretDataKey, logd.Logger{}) 20 | assert.Equal(t, string(dataValue), data) 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /cmd/troubleshoot/oneagentapm.go: -------------------------------------------------------------------------------- 1 | package troubleshoot 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 7 | "github.com/Dynatrace/dynatrace-operator/pkg/util/oneagentapm" 8 | "k8s.io/client-go/rest" 9 | ) 10 | 11 | func checkOneAgentAPM(baseLog logd.Logger, kubeConfig *rest.Config) error { 12 | log := baseLog.WithName("oneAgentAPM") 13 | 14 | logNewCheckf(log, "checking if OneAgentAPM object exists ...") 15 | 16 | exists, err := oneagentapm.Exists(kubeConfig) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | if exists { 22 | return errors.New("OneAgentAPM object still exists - either delete OneAgentAPM objects or fully install the oneAgent operator") 23 | } 24 | 25 | logOkf(log, "OneAgentAPM does not exist") 26 | 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/connectioninfo/oneagent/communication_hosts.go: -------------------------------------------------------------------------------- 1 | package oaconnectioninfo 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 5 | dtclient "github.com/Dynatrace/dynatrace-operator/pkg/clients/dynatrace" 6 | ) 7 | 8 | func GetCommunicationHosts(dk *dynakube.DynaKube) []dtclient.CommunicationHost { 9 | communicationHosts := make([]dtclient.CommunicationHost, 0, len(dk.Status.OneAgent.ConnectionInfoStatus.CommunicationHosts)) 10 | for _, host := range dk.Status.OneAgent.ConnectionInfoStatus.CommunicationHosts { 11 | communicationHosts = append(communicationHosts, dtclient.CommunicationHost{ 12 | Protocol: host.Protocol, 13 | Host: host.Host, 14 | Port: host.Port, 15 | }) 16 | } 17 | 18 | return communicationHosts 19 | } 20 | -------------------------------------------------------------------------------- /cmd/operator/manager_test.go: -------------------------------------------------------------------------------- 1 | package operator 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/consts" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestGetControllerAddFuncs(t *testing.T) { 11 | t.Run("without OLM", func(t *testing.T) { 12 | funcs := getControllerAddFuncs(false) 13 | 14 | assert.Len(t, funcs, 4) // dk, ec, nodes, certs 15 | }) 16 | 17 | t.Run("with OLM", func(t *testing.T) { 18 | funcs := getControllerAddFuncs(true) 19 | 20 | assert.Len(t, funcs, 3) // dk, ec, nodes 21 | }) 22 | 23 | t.Run("without HostAvailabilityDetectionEnvVar", func(t *testing.T) { 24 | t.Setenv(consts.HostAvailabilityDetectionEnvVar, "false") 25 | funcs := getControllerAddFuncs(true) 26 | 27 | assert.Len(t, funcs, 2) // dk, ec 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /pkg/api/validation/dynakube/extensions.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 7 | ) 8 | 9 | const ( 10 | warningExtensionsWithoutK8SMonitoring = "The Dynakube is configured with extensions without an ActiveGate with `kubernetes-monitoring` enabled or the `automatic-kubernetes-api-monitoring` feature flag. You need to ensure that Kubernetes monitoring is setup for this cluster." 11 | ) 12 | 13 | func extensionsWithoutK8SMonitoring(ctx context.Context, dv *Validator, dk *dynakube.DynaKube) string { 14 | if dk.Extensions().IsAnyEnabled() && (!dk.ActiveGate().IsKubernetesMonitoringEnabled() || !dk.FF().IsAutomaticK8sAPIMonitoring()) { 15 | return warningExtensionsWithoutK8SMonitoring 16 | } 17 | 18 | return "" 19 | } 20 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/otelc/consts/consts.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | OtlpAPIEndpointConfigMapName = "dynatrace-otlp-api-endpoint" 5 | 6 | ConfigFieldName = "telemetry.yaml" 7 | TelemetryCollectorConfigmapSuffix = "-telemetry-collector-config" 8 | 9 | CustomTLSCertMountPath = "/tls/custom/telemetry" 10 | 11 | TrustedCAsFile = "rootca.pem" 12 | TrustedCAVolumeMountPath = "/tls/custom/cacerts" 13 | TrustedCAVolumePath = TrustedCAVolumeMountPath + "/" + TrustedCAsFile 14 | 15 | ActiveGateCertFile = "cert.pem" 16 | ActiveGateTLSCertCAVolumeMountPath = "/tls/custom/activegate" 17 | ActiveGateTLSCertVolumePath = ActiveGateTLSCertCAVolumeMountPath + "/" + ActiveGateCertFile 18 | 19 | EnvDataIngestToken = "DT_DATA_INGEST_TOKEN" 20 | ) 21 | -------------------------------------------------------------------------------- /pkg/consts/extensions.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ( 4 | ExtensionsSelfSignedTLSSecretSuffix = "-extension-controller-tls" 5 | 6 | // shared volume name between EEC and OtelC 7 | ExtensionsTokensVolumeName = "tokens" 8 | 9 | ExtensionsControllerSuffix = "-extension-controller" 10 | ExtensionsDatasourceTargetPortName = "collector-com" 11 | ExtensionsDatasourceTargetPort = 14599 12 | 13 | DatasourceTokenSecretKey = "datasource.token" 14 | DatasourceTokenSecretValuePrefix = "dt0x01" 15 | 16 | // DatasourceLabelKey should be placed on all datasource deployments to allow EEC to separate them. 17 | DatasourceLabelKey = "extensions.dynatrace.com/datasource" 18 | // DatabaseDatasourceLabelValue must always be used for database extensions. 19 | DatabaseDatasourceLabelValue = "sql" 20 | ) 21 | -------------------------------------------------------------------------------- /pkg/otelcgen/testdata/receivers_jaeger_only.yaml: -------------------------------------------------------------------------------- 1 | connectors: {} 2 | exporters: {} 3 | extensions: {} 4 | processors: {} 5 | receivers: 6 | jaeger: 7 | protocols: 8 | grpc: 9 | endpoint: test:14250 10 | tls: 11 | cert_file: /run/opensignals/tls/tls.crt 12 | key_file: /run/opensignals/tls/tls.key 13 | thrift_binary: 14 | endpoint: test:6832 15 | thrift_compact: 16 | endpoint: test:6831 17 | thrift_http: 18 | endpoint: test:14268 19 | tls: 20 | cert_file: /run/opensignals/tls/tls.crt 21 | key_file: /run/opensignals/tls/tls.key 22 | service: 23 | extensions: [] 24 | pipelines: {} 25 | -------------------------------------------------------------------------------- /hack/make/doc.mk: -------------------------------------------------------------------------------- 1 | ## Trigger all automatic generated docs creation 2 | .PHONY: 3 | doc: doc/api-ref 4 | 5 | ## Generate API docs for custom resources 6 | doc/api-ref: manifests prerequisites/python 7 | source ./bin/.venv/bin/activate && $(PYTHON) ./hack/doc/custom_resource_params_to_md.py ./config/crd/bases/dynatrace.com_dynakubes.yaml > ./doc/api/dynakube-api-ref.md 8 | source ./bin/.venv/bin/activate && $(PYTHON) ./hack/doc/custom_resource_params_to_md.py ./config/crd/bases/dynatrace.com_edgeconnects.yaml > ./doc/api/edgeconnect-api-ref.md 9 | 10 | ## Create a table containing permissions needed by Operator components 11 | doc/permissions: manifests prerequisites/python 12 | source ./bin/.venv/bin/activate && $(PYTHON) ./hack/doc/role-permissions2md.py ./config/deploy/openshift/openshift-csi.yaml > permissions.md 13 | -------------------------------------------------------------------------------- /hack/build/ci/update-e2e-ondemand-pipeline.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from ruamel.yaml import YAML 4 | 5 | # version file contains a list of strings 6 | version_file = "release-branches.txt" 7 | ondemand_file = ".github/workflows/e2e-tests-ondemand.yaml" 8 | 9 | version = "" 10 | # read versions to list 11 | with open(version_file, "r") as f: 12 | version = [v.strip().replace("origin/", "") for v in f.readlines()][-1] 13 | 14 | yaml = YAML() 15 | yaml.width = 4096 16 | 17 | # read ondemand_file file to dict and update 18 | with open(ondemand_file, "r") as f: 19 | data = yaml.load(f) 20 | data["env"]["branch"] = version 21 | 22 | print(data) 23 | # write ondemand_file renovate file 24 | with open(ondemand_file, "wb") as output: 25 | yaml.indent(mapping=2, sequence=4, offset=2) 26 | yaml.dump(data, output) 27 | -------------------------------------------------------------------------------- /cmd/operator/config.go: -------------------------------------------------------------------------------- 1 | package operator 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const ( 8 | metricsBindAddress = ":8080" 9 | healthProbeBindAddress = ":10080" 10 | 11 | leaderElectionID = "dynatrace-operator-lock" 12 | leaderElectionResourceLock = "leases" 13 | leaderElectionEnvVarRenewDeadline = "LEADER_ELECTION_RENEW_DEADLINE" 14 | leaderElectionEnvVarRetryPeriod = "LEADER_ELECTION_RETRY_PERIOD" 15 | leaderElectionEnvVarLeaseDuration = "LEADER_ELECTION_LEASE_DURATION" 16 | 17 | livezEndpointName = "livez" 18 | livenessEndpointName = "/" + livezEndpointName 19 | 20 | defaultLeaseDuration = int64(30) 21 | defaultRenewDeadline = int64(20) 22 | defaultRetryPeriod = int64(6) 23 | ) 24 | 25 | var log = logd.Get().WithName("operator-command") 26 | -------------------------------------------------------------------------------- /cmd/troubleshoot/namespace.go: -------------------------------------------------------------------------------- 1 | package troubleshoot 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 7 | "github.com/pkg/errors" 8 | corev1 "k8s.io/api/core/v1" 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | ) 11 | 12 | func checkNamespace(ctx context.Context, baseLog logd.Logger, apiReader client.Reader, namespaceName string) error { 13 | log := baseLog.WithName("namespace") 14 | 15 | logNewCheckf(log, "checking if namespace '%s' exists ...", namespaceName) 16 | 17 | var namespace corev1.Namespace 18 | 19 | err := apiReader.Get(ctx, client.ObjectKey{Name: namespaceName}, &namespace) 20 | if err != nil { 21 | return errors.Wrapf(err, "missing namespace '%s'", namespaceName) 22 | } 23 | 24 | logOkf(log, "using namespace '%s'", namespaceName) 25 | 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_dynakubes.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: dynakubes.dynatrace.com 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: dynatrace 13 | name: dynatrace-webhook 14 | path: /convert 15 | # conversionReviewVersions indicates what ConversionReview versions are understood/preferred by the webhook. 16 | # The first version in the list understood by the API server is sent to the webhook. 17 | # The webhook must respond with a ConversionReview object in the same version it received. 18 | conversionReviewVersions: 19 | - v1 20 | - v1beta1 21 | -------------------------------------------------------------------------------- /pkg/api/v1alpha2/edgeconnect/certs.go: -------------------------------------------------------------------------------- 1 | package edgeconnect 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/pkg/errors" 8 | corev1 "k8s.io/api/core/v1" 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | ) 11 | 12 | const TrustedCAKey = "certs" 13 | 14 | func (ec *EdgeConnect) TrustedCAs(ctx context.Context, kubeReader client.Reader) ([]byte, error) { 15 | configName := ec.Spec.CaCertsRef 16 | if configName != "" { 17 | var caConfigMap corev1.ConfigMap 18 | 19 | err := kubeReader.Get(ctx, client.ObjectKey{Name: configName, Namespace: ec.Namespace}, &caConfigMap) 20 | if err != nil { 21 | return nil, errors.WithMessage(err, fmt.Sprintf("failed to get trustedCa from %s configmap", configName)) 22 | } 23 | 24 | return []byte(caConfigMap.Data[TrustedCAKey]), nil 25 | } 26 | 27 | return nil, nil 28 | } 29 | -------------------------------------------------------------------------------- /assets/calico/agent-policy-external-only.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: allow-agent-traffic 5 | spec: 6 | podSelector: 7 | matchLabels: 8 | app: myapp 9 | policyTypes: 10 | - Egress 11 | egress: 12 | # Allow DNS lookup 13 | - to: 14 | - namespaceSelector: 15 | matchLabels: 16 | kubernetes.io/metadata.name: kube-system 17 | ports: 18 | - protocol: UDP 19 | port: 53 20 | - protocol: TCP 21 | port: 53 22 | # Allow external traffic for e.g. Cluster API requests 23 | - to: 24 | - ipBlock: 25 | cidr: 0.0.0.0/0 26 | except: 27 | # blocks private ips, i.e. blocks Pod to Pod communication 28 | - 10.0.0.0/8 29 | - 192.168.0.0/16 30 | - 172.16.0.0/12 31 | ports: [] 32 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_edgeconnects.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: edgeconnects.dynatrace.com 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: dynatrace 13 | name: dynatrace-webhook 14 | path: /convert 15 | # conversionReviewVersions indicates what ConversionReview versions are understood/preferred by the webhook. 16 | # The first version in the list understood by the API server is sent to the webhook. 17 | # The webhook must respond with a ConversionReview object in the same version it received. 18 | conversionReviewVersions: 19 | - v1 20 | - v1beta1 21 | -------------------------------------------------------------------------------- /pkg/api/validation/dynakube/istio.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 7 | "github.com/Dynatrace/dynatrace-operator/pkg/controllers/dynakube/istio" 8 | ) 9 | 10 | const ( 11 | errorNoResources = `No resources for istio available` 12 | errorFailToInitIstioClient = `Failed to initialize istio client` 13 | ) 14 | 15 | func noResourcesAvailable(_ context.Context, dv *Validator, dk *dynakube.DynaKube) string { 16 | if dk.Spec.EnableIstio { 17 | istioClient, err := istio.NewClient(dv.cfg, dk) 18 | if err != nil { 19 | return errorFailToInitIstioClient 20 | } 21 | 22 | enabled, err := istioClient.CheckIstioInstalled() 23 | if !enabled || err != nil { 24 | return errorNoResources 25 | } 26 | } 27 | 28 | return "" 29 | } 30 | -------------------------------------------------------------------------------- /pkg/api/v1alpha2/edgeconnect/edgeconnect_types_test.go: -------------------------------------------------------------------------------- 1 | package edgeconnect 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 | ) 9 | 10 | func TestHostMappings(t *testing.T) { 11 | t.Run("Get HostMappings", func(t *testing.T) { 12 | e := EdgeConnect{ 13 | ObjectMeta: metav1.ObjectMeta{ 14 | Name: "test-edgeconnect", 15 | Namespace: "test-namespace", 16 | }, 17 | Status: EdgeConnectStatus{ 18 | KubeSystemUID: "test-kube-system-uid", 19 | }, 20 | } 21 | got := e.HostMappings() 22 | expected := []HostMapping{ 23 | { 24 | From: "test-edgeconnect.test-namespace.test-kube-system-uid." + kubernetesHostnameSuffix, 25 | To: KubernetesDefaultDNS, 26 | }, 27 | } 28 | require.Equal(t, expected, got) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/kspm/daemonset/certs_test.go: -------------------------------------------------------------------------------- 1 | package daemonset 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 7 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube/activegate" 8 | ) 9 | 10 | func getDynaKubeWithCerts(t *testing.T) dynakube.DynaKube { 11 | t.Helper() 12 | 13 | dk := dynakube.DynaKube{} 14 | dk.ActiveGate().TLSSecretName = "test" 15 | dk.ActiveGate().Capabilities = []activegate.CapabilityDisplayName{activegate.KubeMonCapability.DisplayName} 16 | 17 | return dk 18 | } 19 | 20 | func getDynaKubeWithAutomaticCerts(t *testing.T) dynakube.DynaKube { 21 | t.Helper() 22 | 23 | dk := dynakube.DynaKube{} 24 | dk.ActiveGate().Capabilities = []activegate.CapabilityDisplayName{activegate.KubeMonCapability.DisplayName} 25 | 26 | return dk 27 | } 28 | -------------------------------------------------------------------------------- /assets/docker/codeModulesARM.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine AS builder 2 | 3 | ARG APIURL 4 | ARG APITOKEN 5 | ARG AGENTVERSION 6 | ARG FLAVOR=default 7 | ARG ARCH=arm 8 | 9 | RUN apk update && apk add --update jq 10 | RUN mkdir data 11 | RUN wget "${APIURL}/v1/deployment/installer/agent/unix/paas/version/${AGENTVERSION}/checksum?flavor=${FLAVOR}&arch=${ARCH}&bitness=all&skipMetadata=true" --header "Authorization: Api-Token ${APITOKEN}" -O checksum 12 | RUN wget "${APIURL}/v1/deployment/installer/agent/unix/paas/version/${AGENTVERSION}?flavor=${FLAVOR}&arch=${ARCH}&bitness=all&skipMetadata=true" --header "Authorization: Api-Token ${APITOKEN}" -O /agent.zip 13 | RUN [ "$(jq .sha256 -r checksum)" == "$(sha256sum agent.zip | awk '{ print $1 }')" ] 14 | RUN unzip /agent.zip -d /data 15 | 16 | FROM scratch 17 | COPY --from=builder /data /opt/dynatrace/oneagent 18 | -------------------------------------------------------------------------------- /assets/docker/codeModulesAMD.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine AS builder 2 | 3 | ARG APIURL 4 | ARG APITOKEN 5 | ARG AGENTVERSION 6 | ARG FLAVOR=multidistro 7 | ARG ARCH=x86 8 | 9 | RUN apk update && apk add --update jq 10 | RUN mkdir data 11 | RUN wget "${APIURL}/v1/deployment/installer/agent/unix/paas/version/${AGENTVERSION}/checksum?flavor=${FLAVOR}&arch=${ARCH}&bitness=all&skipMetadata=true" --header "Authorization: Api-Token ${APITOKEN}" -O checksum 12 | RUN wget "${APIURL}/v1/deployment/installer/agent/unix/paas/version/${AGENTVERSION}?flavor=${FLAVOR}&arch=${ARCH}&bitness=all&skipMetadata=true" --header "Authorization: Api-Token ${APITOKEN}" -O /agent.zip 13 | RUN [ "$(jq .sha256 -r checksum)" == "$(sha256sum agent.zip | awk '{ print $1 }')" ] 14 | RUN unzip /agent.zip -d /data 15 | 16 | FROM scratch 17 | COPY --from=builder /data /opt/dynatrace/oneagent 18 | -------------------------------------------------------------------------------- /config/helm/chart/default/tests/Common/webhook/serviceaccount-webhook_test.yaml: -------------------------------------------------------------------------------- 1 | suite: test serviceaccount for webhook 2 | templates: 3 | - Common/webhook/serviceaccount-webhook.yaml 4 | tests: 5 | - it: should exist 6 | set: 7 | platform: kubernetes 8 | asserts: 9 | - isKind: 10 | of: ServiceAccount 11 | - equal: 12 | path: metadata.name 13 | value: dynatrace-webhook 14 | - equal: 15 | path: metadata.namespace 16 | value: NAMESPACE 17 | 18 | - it: should exist 19 | set: 20 | platform: openshift 21 | asserts: 22 | - isKind: 23 | of: ServiceAccount 24 | - equal: 25 | path: metadata.name 26 | value: dynatrace-webhook 27 | - equal: 28 | path: metadata.namespace 29 | value: NAMESPACE 30 | 31 | -------------------------------------------------------------------------------- /test/testdata/edgeconnect/custom-service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: custom-edgeconnect 5 | namespace: dynatrace 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRole 9 | metadata: 10 | name: custom-edgeconnect 11 | rules: 12 | - apiGroups: 13 | - security.openshift.io 14 | resourceNames: 15 | - nonroot 16 | - nonroot-v2 17 | resources: 18 | - securitycontextconstraints 19 | verbs: 20 | - use 21 | --- 22 | apiVersion: rbac.authorization.k8s.io/v1 23 | kind: ClusterRoleBinding 24 | metadata: 25 | name: custom-edgeconnect 26 | namespace: dynatrace 27 | roleRef: 28 | apiGroup: rbac.authorization.k8s.io 29 | kind: ClusterRole 30 | name: custom-edgeconnect 31 | subjects: 32 | - kind: ServiceAccount 33 | name: custom-edgeconnect 34 | namespace: dynatrace 35 | -------------------------------------------------------------------------------- /hack/build/ci/check-image-available.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Usage: check-image-available.sh [timeout] [interval] 3 | 4 | set -eu 5 | 6 | IMAGE="${1:?Image name required (e.g. dynatrace/dynatrace-operator)}" 7 | TAG="${2:?Tag required}" 8 | TIMEOUT="${3:-600}" 9 | INTERVAL="${4:-30}" 10 | ELAPSED=0 11 | 12 | echo "Checking if image ${IMAGE}:${TAG} is available on quay.io" 13 | 14 | while true; do 15 | STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://quay.io/v2/${IMAGE}/manifests/${TAG}") 16 | if [ "$STATUS" -eq 200 ]; then 17 | echo "Image exists" 18 | exit 0 19 | fi 20 | if [ "$ELAPSED" -ge "$TIMEOUT" ]; then 21 | echo "Timeout reached. Image does not exist." 22 | exit 1 23 | fi 24 | echo "Image not available yet. Waiting... ($ELAPSED/$TIMEOUT s)" 25 | sleep "$INTERVAL" 26 | ELAPSED=$((ELAPSED+INTERVAL)) 27 | done 28 | -------------------------------------------------------------------------------- /hack/build/ci/generate-new-helm-index-yaml.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$2" ] 4 | then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | readonly output_dir="${1}" 10 | readonly version_without_prefix="${2}" 11 | 12 | cleanup() { 13 | echo "cleanup" 14 | } 15 | 16 | trap 'cleanup' ERR 17 | 18 | cp "config/helm/repos/stable/index.yaml" "config/helm/repos/stable/index.yaml.previous" 19 | 20 | helm repo index "${output_dir}" \ 21 | --url "https://github.com/Dynatrace/dynatrace-operator/releases/download/v${version_without_prefix}" \ 22 | --merge "./config/helm/repos/stable/index.yaml" 23 | 24 | mv -v "${output_dir}"/index.yaml ./config/helm/repos/stable/index.yaml 25 | 26 | # Fix quotes in place to minimize the diff 27 | sed -i'' -e "s/\"/'/g" ./config/helm/repos/stable/index.yaml 28 | 29 | rm -rf "${output_dir}" 30 | -------------------------------------------------------------------------------- /pkg/clients/edgeconnect/endpoints.go: -------------------------------------------------------------------------------- 1 | package edgeconnect 2 | 3 | // EdgeConnect API 4 | 5 | func (c *client) getEdgeConnectAPIURL() string { 6 | return c.baseURL + "/platform/app-engine/edge-connect/v1" 7 | } 8 | 9 | func (c *client) getEdgeConnectsURL() string { 10 | return c.getEdgeConnectAPIURL() + "/edge-connects" 11 | } 12 | 13 | func (c *client) getEdgeConnectURL(id string) string { 14 | return c.getEdgeConnectsURL() + "/" + id 15 | } 16 | 17 | // Environment API 18 | 19 | func (c *client) getEnvironmentAPIURL() string { 20 | return c.baseURL + "/platform/classic/environment-api/v2" 21 | } 22 | 23 | func (c *client) getSettingsObjectsURL() string { 24 | return c.getEnvironmentAPIURL() + "/settings/objects" 25 | } 26 | 27 | func (c *client) getSettingsObjectsIDURL(objectID string) string { 28 | return c.getSettingsObjectsURL() + "/" + objectID 29 | } 30 | -------------------------------------------------------------------------------- /pkg/util/kubesystem/kubesystem.go: -------------------------------------------------------------------------------- 1 | package kubesystem 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/pkg/errors" 7 | corev1 "k8s.io/api/core/v1" 8 | "k8s.io/apimachinery/pkg/types" 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | ) 11 | 12 | const ( 13 | Namespace = "kube-system" 14 | olmSpecificAnnotation = "olm.operatorNamespace" 15 | ) 16 | 17 | func GetUID(ctx context.Context, clt client.Reader) (types.UID, error) { 18 | kubeSystemNamespace := &corev1.Namespace{} 19 | 20 | err := clt.Get(ctx, client.ObjectKey{Name: Namespace}, kubeSystemNamespace) 21 | if err != nil { 22 | return "", errors.WithStack(err) 23 | } 24 | 25 | return kubeSystemNamespace.UID, nil 26 | } 27 | 28 | func IsDeployedViaOlm(pod corev1.Pod) bool { 29 | _, isDeployedViaOlm := pod.Annotations[olmSpecificAnnotation] 30 | 31 | return isDeployedViaOlm 32 | } 33 | -------------------------------------------------------------------------------- /hack/build/ci/update-renovate-json5.py: -------------------------------------------------------------------------------- 1 | import json5 2 | 3 | # version file contains a list of strings 4 | versionFile = "release-branches.txt" 5 | renovateFile = ".github/renovate.json5" 6 | 7 | # read versions to list 8 | versions = ["$default"] 9 | with open(versionFile, "r") as f: 10 | versions += f.readlines() 11 | versions = [x.strip() for x in versions] 12 | versions = [x.replace("origin/", "") for x in versions] 13 | 14 | # read renovate file to dict and update 15 | with open(renovateFile, "r") as f: 16 | data = json5.load(f) 17 | 18 | data["baseBranches"] = versions 19 | data["packageRules"][0]["matchBaseBranches"] = versions 20 | 21 | # write updated renovate file 22 | with open(renovateFile, "w") as output: 23 | json5.dump(data, output, indent=2) 24 | # editorconfig is set up to add a newline to files 25 | output.write('\n') 26 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/extension/eec/reconciler_integration_test.go: -------------------------------------------------------------------------------- 1 | package eec 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Dynatrace/dynatrace-operator/pkg/util/integrationtests" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestStatefulSet(t *testing.T) { 11 | t.Log("WELCOME") 12 | 13 | clt := integrationtests.SetupTestEnvironment(t) 14 | 15 | dk := getTestDynakube() 16 | 17 | integrationtests.CreateNamespace(t, t.Context(), clt, testNamespaceName) 18 | integrationtests.CreateDynakube(t, t.Context(), clt, dk) 19 | mockTLSSecret(t, clt, dk) 20 | 21 | reconciler := NewReconciler(clt, clt, dk) 22 | err := reconciler.Reconcile(t.Context()) 23 | require.NoError(t, err) 24 | 25 | dk.Spec.Templates.ExtensionExecutionController.UseEphemeralVolume = true 26 | err = reconciler.Reconcile(t.Context()) 27 | require.NoError(t, err) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/mutator/container_test.go: -------------------------------------------------------------------------------- 1 | package mutator 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestContainerExclusionAnnotations(t *testing.T) { 10 | annoations := map[string]string{ 11 | "container.inject.dynatrace.com/falsebar": "false", 12 | "container.inject.dynatrace.com/truebar": "true", 13 | } 14 | 15 | tests := []struct { 16 | name string 17 | expected bool 18 | }{ 19 | { 20 | name: "falsebar", 21 | expected: true, 22 | }, 23 | { 24 | name: "truebar", 25 | expected: false, 26 | }, 27 | { 28 | name: "nobar", 29 | expected: false, 30 | }, 31 | } 32 | 33 | for _, test := range tests { 34 | t.Run(test.name, func(t *testing.T) { 35 | assert.Equal(t, test.expected, checkInjectionAnnotation(annoations, test.name)) 36 | }) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkg/util/kubernetes/objects/k8spod/pod.go: -------------------------------------------------------------------------------- 1 | package k8spod 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/pkg/errors" 7 | corev1 "k8s.io/api/core/v1" 8 | "k8s.io/apimachinery/pkg/types" 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | ) 11 | 12 | func Get(ctx context.Context, clt client.Reader, name, namespace string) (*corev1.Pod, error) { 13 | pod := &corev1.Pod{} 14 | 15 | err := clt.Get(ctx, types.NamespacedName{Name: name, Namespace: namespace}, pod) 16 | if err != nil { 17 | return nil, errors.WithStack(err) 18 | } 19 | 20 | return pod, nil 21 | } 22 | 23 | // GetName returns the name of the pod. 24 | // During the webhook injection the pod.Name is not always set yet, in which case it returns the pod.GeneraName 25 | func GetName(pod corev1.Pod) string { 26 | if pod.Name != "" { 27 | return pod.Name 28 | } 29 | 30 | return pod.GenerateName 31 | } 32 | -------------------------------------------------------------------------------- /pkg/controllers/csi/provisioner/install_test.go: -------------------------------------------------------------------------------- 1 | package csiprovisioner 2 | 3 | import ( 4 | "encoding/base64" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestGetTargetDir(t *testing.T) { 11 | t.Run("version set => folder is the version", func(t *testing.T) { 12 | prov := createProvisioner(t) 13 | dk := createDynaKubeWithVersion(t) 14 | 15 | targetDir := prov.getTargetDir(*dk) 16 | require.Contains(t, targetDir, dk.OneAgent().GetCodeModulesVersion()) 17 | }) 18 | 19 | t.Run("image set => folder is the base64 of the imageURI", func(t *testing.T) { 20 | prov := createProvisioner(t) 21 | dk := createDynaKubeWithImage(t) 22 | 23 | expectedDir := base64.StdEncoding.EncodeToString([]byte(dk.OneAgent().GetCodeModulesImage())) 24 | targetDir := prov.getTargetDir(*dk) 25 | require.Contains(t, targetDir, expectedDir) 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /test/helpers/kubeobjects/statefulset/get.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package statefulset 4 | 5 | import ( 6 | "context" 7 | 8 | appsv1 "k8s.io/api/apps/v1" 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | "sigs.k8s.io/e2e-framework/klient/k8s/resources" 11 | ) 12 | 13 | type Query struct { 14 | ctx context.Context 15 | resource *resources.Resources 16 | objectKey client.ObjectKey 17 | } 18 | 19 | func NewQuery(ctx context.Context, resource *resources.Resources, objectKey client.ObjectKey) *Query { 20 | return &Query{ 21 | ctx: ctx, 22 | resource: resource, 23 | objectKey: objectKey, 24 | } 25 | } 26 | 27 | func (query *Query) Get() (appsv1.StatefulSet, error) { 28 | var stateFulSet appsv1.StatefulSet 29 | err := query.resource.Get(query.ctx, query.objectKey.Name, query.objectKey.Namespace, &stateFulSet) 30 | 31 | return stateFulSet, err 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/e2e-cleanup-kubernetes-settings.yaml: -------------------------------------------------------------------------------- 1 | name: E2E cleanup Kubernetes settings 2 | 3 | on: 4 | schedule: 5 | # every Sunday at 00:00 UTC 6 | - cron: 0 0 * * 0 7 | workflow_dispatch: 8 | 9 | jobs: 10 | cleanup-kubernetes-settings: 11 | name: Cleanup Kubernetes settings 12 | environment: E2E 13 | runs-on: 14 | - self-hosted 15 | - operator-e2e 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 19 | with: 20 | sparse-checkout: ./hack/tenant/cleanup-kubernetes-settings.sh 21 | - name: Run cleanup script 22 | shell: bash 23 | env: 24 | TENANT_NAME: ${{ secrets.TENANT1_NAME }} 25 | TENANT_APITOKEN: ${{ secrets.TENANT1_APITOKEN }} 26 | run: | 27 | ./hack/tenant/cleanup-kubernetes-settings.sh 28 | -------------------------------------------------------------------------------- /pkg/util/conditions/error_test.go: -------------------------------------------------------------------------------- 1 | package conditions 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | pkgerrors "github.com/pkg/errors" 8 | "github.com/stretchr/testify/assert" 9 | k8serrors "k8s.io/apimachinery/pkg/api/errors" 10 | ) 11 | 12 | func TestIsKubeApiError(t *testing.T) { 13 | assert.False(t, IsKubeAPIError(nil), "Nil error should not be a Kube API error") 14 | assert.False(t, IsKubeAPIError(errors.New("Some error")), "Non-Kube API error should not be a Kube API error") 15 | assert.True(t, IsKubeAPIError(k8serrors.NewBadRequest("Bad request")), "Kube API error should be a Kube API error") 16 | 17 | t.Run("wrapped error", func(t *testing.T) { 18 | var err error 19 | err = k8serrors.NewBadRequest("Bad request") 20 | err = pkgerrors.WithStack(err) 21 | assert.True(t, IsKubeAPIError(err), "Kube API error should be a Kube API error even if wrapped") 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /test/helpers/kubeobjects/job/wait.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package job 4 | 5 | import ( 6 | "context" 7 | "testing" 8 | "time" 9 | 10 | "github.com/stretchr/testify/require" 11 | "sigs.k8s.io/e2e-framework/klient/wait" 12 | "sigs.k8s.io/e2e-framework/klient/wait/conditions" 13 | "sigs.k8s.io/e2e-framework/pkg/envconf" 14 | "sigs.k8s.io/e2e-framework/pkg/features" 15 | ) 16 | 17 | func WaitForJobsDeletionWithOwner(ownerName string, namespace string) features.Func { 18 | return func(ctx context.Context, t *testing.T, envConfig *envconf.Config) context.Context { 19 | resources := envConfig.Client().Resources() 20 | jobs := GetJobsForOwner(ctx, t, resources, ownerName, namespace) 21 | 22 | if len(jobs.Items) > 0 { 23 | err := wait.For(conditions.New(resources).ResourcesDeleted(&jobs), wait.WithTimeout(1*time.Minute)) 24 | require.NoError(t, err) 25 | } 26 | 27 | return ctx 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/helpers/tenant/secrets_test.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | package tenant 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | const testSecretFileContent = "apiUrl: apiUrl\napiToken: apiToken" 15 | 16 | func TestNewFromConfig(t *testing.T) { 17 | workingDir := t.TempDir() 18 | 19 | secretsPath := filepath.Join(workingDir, "..", "testdata", "Secrets") 20 | require.NoError(t, os.MkdirAll(secretsPath, 0655)) 21 | 22 | require.NoError(t, os.WriteFile(filepath.Join(secretsPath, "Secrets-test.yaml"), 23 | []byte(testSecretFileContent), 0600)) 24 | 25 | tenantSecrets, err := newFromConfig(filepath.Join(secretsPath, "Secrets-test.yaml")) 26 | 27 | require.NoError(t, err) 28 | assert.Equal(t, "apiUrl", tenantSecrets.APIURL) 29 | assert.Equal(t, "apiToken", tenantSecrets.APIToken) 30 | } 31 | -------------------------------------------------------------------------------- /config/helm/chart/default/templates/Common/operator/serviceaccount-operator.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Dynatrace LLC 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 | apiVersion: v1 15 | kind: ServiceAccount 16 | metadata: 17 | name: dynatrace-operator 18 | namespace: {{ .Release.Namespace }} 19 | labels: 20 | {{- include "dynatrace-operator.operatorLabels" . | nindent 4 }} 21 | -------------------------------------------------------------------------------- /config/helm/chart/default/templates/Common/webhook/serviceaccount-webhook.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Dynatrace LLC 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 | apiVersion: v1 15 | kind: ServiceAccount 16 | metadata: 17 | name: dynatrace-webhook 18 | namespace: {{ .Release.Namespace }} 19 | labels: 20 | {{- include "dynatrace-operator.webhookLabels" . | nindent 4 }} 21 | 22 | -------------------------------------------------------------------------------- /hack/build/ci/generate-helm-package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$3" ] 4 | then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | readonly secring="${1}" 10 | readonly passphrase="${2}" 11 | readonly output_dir="${3}" 12 | readonly version_without_prefix="${4}" 13 | 14 | mkdir -p ~/.gnupg 15 | echo "${secring}" | base64 -d >~/.gnupg/secring.gpg 16 | echo "${passphrase}" >~/.gnupg/passphrase 17 | 18 | cleanup() { 19 | rm -f ~/.gnupg/secring.gpg 20 | rm -f ~/.gnupg/passphrase 21 | } 22 | 23 | trap 'cleanup' ERR 24 | 25 | helm package \ 26 | "./config/helm/chart/default/" \ 27 | -d "${output_dir}" \ 28 | --app-version "${version_without_prefix}" \ 29 | --version "${version_without_prefix}" \ 30 | --sign \ 31 | --key "Dynatrace LLC" \ 32 | --keyring ~/.gnupg/secring.gpg \ 33 | --passphrase-file ~/.gnupg/passphrase 34 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/dynatraceapi/status.go: -------------------------------------------------------------------------------- 1 | package dynatraceapi 2 | 3 | import ( 4 | "net/http" 5 | 6 | dtclient "github.com/Dynatrace/dynatrace-operator/pkg/clients/dynatrace" 7 | "github.com/pkg/errors" 8 | ) 9 | 10 | const ( 11 | NoError = 0 12 | ) 13 | 14 | func IsUnreachable(err error) bool { 15 | var serverErr dtclient.ServerError 16 | if errors.As(err, &serverErr) && (serverErr.Code == http.StatusTooManyRequests || serverErr.Code == http.StatusServiceUnavailable) { 17 | return true 18 | } 19 | 20 | return false 21 | } 22 | 23 | func StatusCode(err error) int { 24 | var serverErr dtclient.ServerError 25 | if errors.As(err, &serverErr) { 26 | return serverErr.Code 27 | } 28 | 29 | return 0 30 | } 31 | 32 | func Message(err error) string { 33 | var serverErr dtclient.ServerError 34 | if errors.As(err, &serverErr) { 35 | return serverErr.Message 36 | } 37 | 38 | return "" 39 | } 40 | -------------------------------------------------------------------------------- /pkg/api/validation/edgeconnect/name.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/Dynatrace/dynatrace-operator/pkg/api/v1alpha2/edgeconnect" 8 | ) 9 | 10 | const ( 11 | errorNameTooLong = `The length limit for the name of a EdgeConnect is %d, because it is the base for the name of resources related to the EdgeConnect. 12 | The limit is necessary because kubernetes uses the name of some resources for the label value, which has a limit of 63 characters. (see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set)` 13 | ) 14 | 15 | func nameTooLong(_ context.Context, _ *Validator, ec *edgeconnect.EdgeConnect) string { 16 | edgeConnectName := ec.Name 17 | if edgeConnectName != "" && len(edgeConnectName) > edgeconnect.MaxNameLength { 18 | return fmt.Sprintf(errorNameTooLong, edgeconnect.MaxNameLength) 19 | } 20 | 21 | return "" 22 | } 23 | -------------------------------------------------------------------------------- /pkg/util/conditions/status.go: -------------------------------------------------------------------------------- 1 | package conditions 2 | 3 | import ( 4 | "k8s.io/apimachinery/pkg/api/meta" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | const ( 9 | StatusUpdatedReason = "StatusUpdated" 10 | StatusOutdatedReason = "StatusOutdated" 11 | ) 12 | 13 | func SetStatusUpdated(conditions *[]metav1.Condition, conditionType, msg string) { 14 | condition := metav1.Condition{ 15 | Type: conditionType, 16 | Status: metav1.ConditionTrue, 17 | Reason: StatusUpdatedReason, 18 | Message: msg, 19 | } 20 | _ = meta.SetStatusCondition(conditions, condition) 21 | } 22 | 23 | func SetStatusOutdated(conditions *[]metav1.Condition, conditionType, msg string) { 24 | condition := metav1.Condition{ 25 | Type: conditionType, 26 | Status: metav1.ConditionFalse, 27 | Reason: StatusOutdatedReason, 28 | Message: msg, 29 | } 30 | _ = meta.SetStatusCondition(conditions, condition) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/handler/injection/deprecated_test.go: -------------------------------------------------------------------------------- 1 | package injection 2 | 3 | import ( 4 | "testing" 5 | 6 | podattr "github.com/Dynatrace/dynatrace-bootstrapper/cmd/configure/attributes/pod" 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func Test_setDeprecatedAttributes(t *testing.T) { 12 | t.Run("set deprecated attribute according to current attribute", func(t *testing.T) { 13 | attrs := podattr.Attributes{ 14 | ClusterInfo: podattr.ClusterInfo{ 15 | ClusterUID: "testID", 16 | }, 17 | } 18 | 19 | setDeprecatedAttributes(&attrs) 20 | 21 | assertDeprecatedAttributes(t, attrs) 22 | }) 23 | } 24 | 25 | func assertDeprecatedAttributes(t *testing.T, attrs podattr.Attributes) { 26 | t.Helper() 27 | 28 | depValue, ok := attrs.UserDefined[deprecatedClusterIDKey] 29 | require.True(t, ok) 30 | assert.Equal(t, attrs.ClusterUID, depValue) 31 | } 32 | -------------------------------------------------------------------------------- /cmd/metadata/writer.go: -------------------------------------------------------------------------------- 1 | package metadata 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | func parseAttributes(attributesFlag string) (string, error) { 10 | if attributesFlag == "" { 11 | return "", errors.New("node-attributes flag cannot be empty") 12 | } 13 | 14 | pairs := strings.Split(attributesFlag, ",") 15 | validPairs := make([]string, 0, len(pairs)) 16 | 17 | for _, pair := range pairs { 18 | trimmed := strings.TrimSpace(pair) 19 | if trimmed == "" { 20 | continue 21 | } 22 | 23 | if !strings.Contains(trimmed, "=") { 24 | return "", errors.Errorf("invalid attribute format: %s (expected key=value)", trimmed) 25 | } 26 | 27 | validPairs = append(validPairs, trimmed) 28 | } 29 | 30 | if len(validPairs) == 0 { 31 | return "", errors.New("no valid attributes found in node-attributes flag") 32 | } 33 | 34 | return strings.Join(validPairs, "\n") + "\n", nil 35 | } 36 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/annotations/annotations.go: -------------------------------------------------------------------------------- 1 | package annotations 2 | 3 | import "github.com/Dynatrace/dynatrace-operator/pkg/webhook/mutation/pod/mutator" 4 | 5 | func SetInjected(mutationRequest *mutator.MutationRequest, injectedAnnotation, reasonAnnotation string) { 6 | if mutationRequest.Pod.Annotations == nil { 7 | mutationRequest.Pod.Annotations = make(map[string]string) 8 | } 9 | 10 | mutationRequest.Pod.Annotations[injectedAnnotation] = "true" 11 | delete(mutationRequest.Pod.Annotations, reasonAnnotation) 12 | } 13 | 14 | func SetNotInjected(mutationRequest *mutator.MutationRequest, injectedAnnotation, reasonAnnotation, reasonValue string) { 15 | if mutationRequest.Pod.Annotations == nil { 16 | mutationRequest.Pod.Annotations = make(map[string]string) 17 | } 18 | 19 | mutationRequest.Pod.Annotations[injectedAnnotation] = "false" 20 | mutationRequest.Pod.Annotations[reasonAnnotation] = reasonValue 21 | } 22 | -------------------------------------------------------------------------------- /pkg/injection/codemodule/installer/zip/zip_test.go: -------------------------------------------------------------------------------- 1 | package zip 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/klauspost/compress/zip" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestExtractZip(t *testing.T) { 11 | t.Run("file nil", func(t *testing.T) { 12 | tmpDir := t.TempDir() 13 | extractor := createTestExtractor() 14 | err := extractor.ExtractZip(nil, tmpDir) 15 | require.EqualError(t, err, "file is nil") 16 | }) 17 | t.Run("unzip test zip file", func(t *testing.T) { 18 | tmpDir := t.TempDir() 19 | zipFile := SetupTestArchive(t, TestRawZip) 20 | 21 | defer func() { _ = zipFile.Close() }() 22 | 23 | fileInfo, err := zipFile.Stat() 24 | require.NoError(t, err) 25 | 26 | reader, err := zip.NewReader(zipFile, fileInfo.Size()) 27 | require.NoError(t, err) 28 | 29 | err = extractFilesFromZip(tmpDir, reader) 30 | require.NoError(t, err) 31 | testUnpackedArchive(t, tmpDir) 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/util/conditions/time.go: -------------------------------------------------------------------------------- 1 | package conditions 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 5 | "github.com/Dynatrace/dynatrace-operator/pkg/util/timeprovider" 6 | "k8s.io/apimachinery/pkg/api/meta" 7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 | ) 9 | 10 | // IsOutdated determines if a given is considered outdated according to the DynaKube's FeatureApiRequestThreshold 11 | // This is used for those conditions that are (also) used for limiting API requests. 12 | func IsOutdated(timeProvider *timeprovider.Provider, dk *dynakube.DynaKube, conditionType string) bool { 13 | condition := meta.FindStatusCondition(*dk.Conditions(), conditionType) 14 | if condition == nil { 15 | return true 16 | } 17 | 18 | return (condition.Status == metav1.ConditionFalse && condition.Reason != OptionalScopeMissingReason) || timeProvider.IsOutdated(&condition.LastTransitionTime, dk.APIRequestThreshold()) 19 | } 20 | -------------------------------------------------------------------------------- /.github/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check linting and unit tests before commiting 4 | # if linting fails the commit will be aborted and the linting will start auto fixing 5 | # if unit tests fail the commit will be aborted 6 | 7 | # Linting 8 | 9 | echo Shell: "${SHELL}" 10 | 11 | echo Linting markdown files... 12 | make markdown/lint 13 | 14 | ## this will retrieve all of the .go files that have been 15 | ## changed since the last commit 16 | STAGED_GO_FILES=$(git diff --cached --name-only -- '*.go') 17 | 18 | ## we can check to see if this is empty 19 | if [[ ${STAGED_GO_FILES} == "" ]]; then 20 | echo "No Go Files to Update" 21 | exit 0 22 | fi 23 | 24 | make go/lint 25 | res=${?} 26 | if [[ ${res} -ne 0 ]]; then 27 | echo "Linting failed" 28 | exit 2 29 | fi 30 | 31 | echo "Run unit tests..." 32 | make go/test 33 | res=${?} 34 | if [[ ${res} -ne 0 ]]; then 35 | echo "Unit test failed" 36 | exit 2 37 | fi 38 | echo 39 | -------------------------------------------------------------------------------- /cmd/troubleshoot/logger_test.go: -------------------------------------------------------------------------------- 1 | package troubleshoot 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "testing" 7 | 8 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | func runWithTestLogger(function func(log logd.Logger)) string { 14 | logBuffer := bytes.Buffer{} 15 | logger := NewTroubleshootLoggerToWriter(&logBuffer) 16 | function(logger) 17 | 18 | return logBuffer.String() 19 | } 20 | 21 | func getNullLogger(t *testing.T) logd.Logger { 22 | devNull, err := os.Open(os.DevNull) 23 | require.NoError(t, err) 24 | 25 | return NewTroubleshootLoggerToWriter(devNull) 26 | } 27 | 28 | func TestTroubleshootLogger(t *testing.T) { 29 | const testLogOutput = "test log output" 30 | 31 | logOutput := runWithTestLogger(func(log logd.Logger) { 32 | logInfof(log, testLogOutput) 33 | }) 34 | 35 | assert.Contains(t, logOutput, testLogOutput) 36 | } 37 | -------------------------------------------------------------------------------- /pkg/api/validation/dynakube/featureflag.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/Dynatrace/dynatrace-operator/pkg/api/exp" 9 | "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 10 | ) 11 | 12 | const ( 13 | warningFeatureFlagDeprecated = `Feature flag %s is deprecated.` 14 | ) 15 | 16 | var deprecatedFeatureFlags = []string{ 17 | exp.OAProxyIgnoredKey, //nolint:staticcheck 18 | exp.AGUpdatesKey, //nolint:staticcheck 19 | exp.AGDisableUpdatesKey, //nolint:staticcheck 20 | } 21 | 22 | func deprecatedFeatureFlag(_ context.Context, _ *Validator, dk *dynakube.DynaKube) string { 23 | results := strings.Builder{} 24 | 25 | for _, flag := range deprecatedFeatureFlags { 26 | if dk.Annotations != nil && dk.Annotations[flag] != "" { 27 | results.WriteString(fmt.Sprintf(warningFeatureFlagDeprecated, flag)) 28 | } 29 | } 30 | 31 | return results.String() 32 | } 33 | -------------------------------------------------------------------------------- /pkg/api/validation/dynakube/webhook.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | latest "github.com/Dynatrace/dynatrace-operator/pkg/api/latest/dynakube" 5 | v1beta3 "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta3/dynakube" 6 | v1beta4 "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta4/dynakube" 7 | v1beta5 "github.com/Dynatrace/dynatrace-operator/pkg/api/v1beta5/dynakube" 8 | ctrl "sigs.k8s.io/controller-runtime" 9 | ) 10 | 11 | func SetupWebhookWithManager(mgr ctrl.Manager) error { 12 | validator := New(mgr.GetAPIReader(), mgr.GetConfig()) 13 | 14 | if err := v1beta3.SetupWebhookWithManager(mgr, validator); err != nil { 15 | return err 16 | } 17 | 18 | if err := v1beta4.SetupWebhookWithManager(mgr, validator); err != nil { 19 | return err 20 | } 21 | 22 | if err := v1beta5.SetupWebhookWithManager(mgr, validator); err != nil { 23 | return err 24 | } 25 | 26 | return latest.SetupWebhookWithManager(mgr, validator) 27 | } 28 | -------------------------------------------------------------------------------- /pkg/otelcgen/exporters.go: -------------------------------------------------------------------------------- 1 | package otelcgen 2 | 3 | import ( 4 | "go.opentelemetry.io/collector/component" 5 | "go.opentelemetry.io/collector/config/configtls" 6 | ) 7 | 8 | var ( 9 | otlphttp = component.MustNewID("otlphttp") 10 | ) 11 | 12 | func (c *Config) buildExporters() map[component.ID]component.Config { 13 | serverConfig := &ServerConfig{ 14 | Endpoint: c.buildExportersEndpoint(), 15 | } 16 | 17 | if c.caFile != "" { 18 | serverConfig.TLSSetting = &TLSSetting{ 19 | Config: configtls.Config{ 20 | CAFile: c.caFile, 21 | }, 22 | } 23 | if c.includeSystemCACertsPool { 24 | serverConfig.TLSSetting.IncludeSystemCACertsPool = c.includeSystemCACertsPool 25 | } 26 | } 27 | 28 | if c.apiToken != "" { 29 | serverConfig.Headers = make(map[string]string) 30 | serverConfig.Headers["Authorization"] = "Api-Token " + c.apiToken 31 | } 32 | 33 | return map[component.ID]component.Config{ 34 | otlphttp: serverConfig, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /pkg/controllers/dynakube/deploymentmetadata/config.go: -------------------------------------------------------------------------------- 1 | package deploymentmetadata 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/logd" 5 | ) 6 | 7 | const ( 8 | orchestrationTech = "Operator" 9 | 10 | operatorScriptVersionKey = "script_version" 11 | orchestratorIDKey = "orchestrator_id" 12 | orchestrationTechKey = "orchestration_tech" 13 | 14 | ApplicationMonitoringDeploymentType = "application_monitoring" 15 | ClassicFullStackDeploymentType = "classic_fullstack" 16 | CloudNativeDeploymentType = "cloud_native_fullstack" 17 | HostMonitoringDeploymentType = "host_monitoring" 18 | 19 | EnvDtDeploymentMetadata = "DT_DEPLOYMENT_METADATA" 20 | EnvDtOperatorVersion = "DT_OPERATOR_VERSION" 21 | 22 | OneAgentMetadataKey = "oneagent" 23 | ActiveGateMetadataKey = "activegate" 24 | OperatorVersionKey = "operator" 25 | ) 26 | 27 | var ( 28 | log = logd.Get().WithName("dynakube-deployment-metadata") 29 | ) 30 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/pod/mutator/interface.go: -------------------------------------------------------------------------------- 1 | package mutator 2 | 3 | type Mutator interface { 4 | // IsEnabled returns true if the mutator needs to be executed for the given request. 5 | // This is used to filter out mutators that are not needed for the given request. 6 | IsEnabled(request *BaseRequest) bool 7 | 8 | // IsInjected returns true if the mutator has already injected into the pod of the given request. 9 | // This is used during reinvocation to prevent multiple injections. 10 | IsInjected(request *BaseRequest) bool 11 | 12 | // Mutate mutates the elements of the given MutationRequest, specifically the pod and installContainer. 13 | Mutate(request *MutationRequest) error 14 | 15 | // Reinvocation mutates the pod of the given ReinvocationRequest. 16 | // It only mutates the parts of the pod that haven't been mutated yet. (example: another webhook mutated the pod after our webhook was executed) 17 | Reinvoke(request *ReinvocationRequest) bool 18 | } 19 | -------------------------------------------------------------------------------- /pkg/api/latest/dynakube/activegate/status.go: -------------------------------------------------------------------------------- 1 | package activegate 2 | 3 | import ( 4 | "github.com/Dynatrace/dynatrace-operator/pkg/api/shared/communication" 5 | "github.com/Dynatrace/dynatrace-operator/pkg/api/status" 6 | ) 7 | 8 | // +kubebuilder:object:generate=true 9 | 10 | type Status struct { 11 | status.VersionStatus `json:",inline"` 12 | 13 | // Information about Active Gate's connections 14 | ConnectionInfo communication.ConnectionInfo `json:"connectionInfoStatus,omitempty"` 15 | 16 | // The ClusterIPs set by Kubernetes on the ActiveGate Service created by the Operator 17 | ServiceIPs []string `json:"serviceIPs,omitempty"` 18 | } 19 | 20 | // GetImage provides the image reference set in Status for the ActiveGate. 21 | // Format: repo@sha256:digest. 22 | func (ag *Status) GetImage() string { 23 | return ag.ImageID 24 | } 25 | 26 | // GetVersion provides version set in Status for the ActiveGate. 27 | func (ag *Status) GetVersion() string { 28 | return ag.Version 29 | } 30 | -------------------------------------------------------------------------------- /config/helm/chart/default/templates/Common/csi/serviceaccount-csi.yaml: -------------------------------------------------------------------------------- 1 | {{ if eq (include "dynatrace-operator.needCSI" .) "true" }} 2 | # Copyright 2021 Dynatrace LLC 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 | apiVersion: v1 16 | kind: ServiceAccount 17 | metadata: 18 | name: dynatrace-oneagent-csi-driver 19 | namespace: {{ .Release.Namespace }} 20 | labels: 21 | {{- include "dynatrace-operator.csiLabels" . | nindent 4 }} 22 | {{- end -}} 23 | -------------------------------------------------------------------------------- /config/helm/chart/default/tests/Common/operator/serviceaccount-operator_test.yaml: -------------------------------------------------------------------------------- 1 | suite: test serviceaccount for dynatrace operator 2 | templates: 3 | - Common/operator/serviceaccount-operator.yaml 4 | tests: 5 | - it: should exist 6 | set: 7 | platform: kubernetes 8 | asserts: 9 | - isKind: 10 | of: ServiceAccount 11 | - equal: 12 | path: metadata.name 13 | value: dynatrace-operator 14 | - equal: 15 | path: metadata.namespace 16 | value: NAMESPACE 17 | - isNotEmpty: 18 | path: metadata.labels 19 | 20 | - it: should exist 21 | set: 22 | platform: openshift 23 | asserts: 24 | - isKind: 25 | of: ServiceAccount 26 | - equal: 27 | path: metadata.name 28 | value: dynatrace-operator 29 | - equal: 30 | path: metadata.namespace 31 | value: NAMESPACE 32 | - isNotEmpty: 33 | path: metadata.labels 34 | 35 | --------------------------------------------------------------------------------