mirror of https://github.com/grafana/grafana.git
				
				
				
			Chore: Add grafana-apiserver (#70721)
* add grafana-apiserver * remove watchset & move provisioning and http server to background services * remove scheme * otel fixes (#70874) * remove module ProvideRegistry test * use certgenerator from apiserver package * Control collector/pdata from going to v1.0.0-rc8 (as Tempo 1.5.1 would have it)
This commit is contained in:
		
							parent
							
								
									8ced4343f3
								
							
						
					
					
						commit
						52121b7165
					
				|  | @ -99,6 +99,7 @@ | |||
| /pkg/server/ @grafana/backend-platform | ||||
| /pkg/services/annotations/ @grafana/backend-platform | ||||
| /pkg/services/apikey/ @grafana/grafana-authnz-team | ||||
| /pkg/services/certgenerator @grafana/grafana-app-platform-squad | ||||
| /pkg/services/cleanup/ @grafana/backend-platform | ||||
| /pkg/services/contexthandler/ @grafana/backend-platform | ||||
| /pkg/services/correlations/ @grafana/backend-platform | ||||
|  | @ -108,6 +109,7 @@ | |||
| /pkg/services/dashboardversion/ @grafana/backend-platform | ||||
| /pkg/services/encryption/ @grafana/backend-platform | ||||
| /pkg/services/folder/ @grafana/backend-platform | ||||
| /pkg/services/grafana-apiserver @grafana/grafana-app-platform-squad | ||||
| /pkg/services/hooks/ @grafana/backend-platform | ||||
| /pkg/services/kmsproviders/ @grafana/backend-platform | ||||
| /pkg/services/licensing/ @grafana/backend-platform | ||||
|  |  | |||
|  | @ -82,6 +82,11 @@ linters = ["stylecheck"] | |||
| text = "ST1001" | ||||
| 
 | ||||
| # Enable when appropriate | ||||
| # http.CloseNotifier has been deprecated since Go 1.11 and an alternative has been available since Go 1.7: We currently need it in pkg/web/response_writer.go. | ||||
| [[issues.exclude-rules]] | ||||
| linters = ["staticcheck"] | ||||
| text = "SA1019: http.CloseNotifier" | ||||
| 
 | ||||
| # strings.Title has been deprecated since Go 1.18 and an alternative has been available since Go 1.0: The rule Title uses for word boundaries does not handle Unicode punctuation properly. | ||||
| # Use golang.org/x/text/cases instead. | ||||
| [[issues.exclude-rules]] | ||||
|  |  | |||
|  | @ -128,6 +128,7 @@ Experimental features might be changed or removed without prior notice. | |||
| | `transformationsRedesign`                   | Enables the transformations redesign                                                                         | | ||||
| | `mlExpressions`                             | Enable support for Machine Learning in server-side expressions                                               | | ||||
| | `disableTraceQLStreaming`                   | Disables the option to stream the response of TraceQL queries of the Tempo data source                       | | ||||
| | `grafanaAPIServer`                          | Enable Kubernetes API Server for Grafana resources                                                           | | ||||
| 
 | ||||
| ## Development feature toggles | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										107
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										107
									
								
								go.mod
								
								
								
								
							|  | @ -13,13 +13,19 @@ replace github.com/denisenkom/go-mssqldb => github.com/grafana/go-mssqldb v0.9.2 | |||
| replace github.com/docker/docker => github.com/moby/moby v23.0.4+incompatible | ||||
| 
 | ||||
| // contains openapi encoder fixes. remove ASAP | ||||
| replace cuelang.org/go => github.com/sdboyer/cue v0.5.0-beta.2.0.20230712135403-bdc4772ae055 | ||||
| replace cuelang.org/go => github.com/sdboyer/cue v0.5.0-beta.2.0.20230712135403-bdc4772ae055 // @grafana/grafana-as-code | ||||
| 
 | ||||
| // For some insane reason, client-go seems to have a broken v12.0.0 tag on it that forces us to | ||||
| // hoist a replace statement. | ||||
| replace k8s.io/client-go => k8s.io/client-go v0.25.3 | ||||
| // TODO: following otel replaces to pin the libraries so k8s.io/apiserver doesn't downgrade us inadvertantly | ||||
| // will need bumps as we upgrade otel in Grafana | ||||
| replace go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // @grafana/backend-platform | ||||
| 
 | ||||
| require k8s.io/apimachinery v0.26.2 // @grafana/backend-platform | ||||
| replace go.opentelemetry.io/otel => go.opentelemetry.io/otel v1.16.0 // @grafana/backend-platform | ||||
| 
 | ||||
| replace go.opentelemetry.io/otel/trace => go.opentelemetry.io/otel/trace v1.16.0 // @grafana/backend-platform | ||||
| 
 | ||||
| replace go.opentelemetry.io/otel/metric => go.opentelemetry.io/otel/metric v1.16.0 // @grafana/backend-platform | ||||
| 
 | ||||
| replace go.opentelemetry.io/collector/pdata => go.opentelemetry.io/collector/pdata v0.50.0 // @grafana/backend-platform | ||||
| 
 | ||||
| // Override Prometheus version because Prometheus v2.X is tagged as v0.X for Go modules purposes and Go assumes | ||||
| // that v1.Y is higher than v0.X, so when we resolve dependencies if any dependency imports v1.Y we'd | ||||
|  | @ -99,16 +105,16 @@ require ( | |||
| 	github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae // @grafana/backend-platform | ||||
| 	github.com/yalue/merged_fs v1.2.2 // @grafana/grafana-as-code | ||||
| 	github.com/yudai/gojsondiff v1.0.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/collector/model v0.46.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/collector/model v0.50.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/collector/pdata v1.0.0-rc8 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.37.0 // @grafana/grafana-operator-experience-squad | ||||
| 	go.opentelemetry.io/otel v1.14.0 // @grafana/alerting-squad-backend | ||||
| 	go.opentelemetry.io/otel/exporters/jaeger v1.10.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/otel/sdk v1.14.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/otel/trace v1.14.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/otel/sdk v1.16.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/otel/trace v1.16.0 // @grafana/backend-platform | ||||
| 	golang.org/x/crypto v0.11.0 // @grafana/backend-platform | ||||
| 	golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // @grafana/alerting-squad-backend | ||||
| 	golang.org/x/net v0.10.0 // @grafana/grafana-bi-squad | ||||
| 	golang.org/x/oauth2 v0.7.0 // @grafana/grafana-authnz-team | ||||
| 	golang.org/x/oauth2 v0.8.0 // @grafana/grafana-authnz-team | ||||
| 	golang.org/x/sync v0.3.0 // @grafana/alerting-squad-backend | ||||
| 	golang.org/x/time v0.3.0 // @grafana/backend-platform | ||||
| 	golang.org/x/tools v0.7.0 // @grafana/grafana-as-code | ||||
|  | @ -121,7 +127,7 @@ require ( | |||
| 	gopkg.in/mail.v2 v2.3.1 // @grafana/backend-platform | ||||
| 	gopkg.in/yaml.v2 v2.4.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-squad-backend | ||||
| 	xorm.io/builder v0.3.6 // indirect | ||||
| 	xorm.io/builder v0.3.6 // indirect; @grafana/backend-platform | ||||
| 	xorm.io/core v0.7.3 // @grafana/backend-platform | ||||
| 	xorm.io/xorm v0.8.2 // @grafana/alerting-squad-backend | ||||
| ) | ||||
|  | @ -134,14 +140,13 @@ require ( | |||
| 	github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect | ||||
| 	github.com/Azure/go-autorest/logger v0.2.1 // indirect | ||||
| 	github.com/Azure/go-autorest/tracing v0.6.0 // indirect | ||||
| 	github.com/FZambia/eagle v0.0.2 // indirect | ||||
| 	github.com/FZambia/eagle v0.1.0 // indirect | ||||
| 	github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect | ||||
| 	github.com/andybalholm/brotli v1.0.4 // @grafana/partner-datasources | ||||
| 	github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect | ||||
| 	github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect | ||||
| 	github.com/beorn7/perks v1.0.1 // indirect | ||||
| 	github.com/cenkalti/backoff/v4 v4.2.1 // indirect | ||||
| 	github.com/centrifugal/protocol v0.10.0 // indirect | ||||
| 	github.com/cespare/xxhash/v2 v2.2.0 // indirect | ||||
| 	github.com/cheekybits/genny v1.0.0 // indirect | ||||
| 	github.com/cockroachdb/apd/v2 v2.0.2 // indirect | ||||
|  | @ -164,7 +169,7 @@ require ( | |||
| 	github.com/go-openapi/validate v0.22.1 // indirect | ||||
| 	github.com/golang-jwt/jwt/v4 v4.5.0 // @grafana/backend-platform | ||||
| 	github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect | ||||
| 	github.com/golang/glog v1.0.0 // indirect | ||||
| 	github.com/golang/glog v1.1.0 // indirect | ||||
| 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | ||||
| 	github.com/golang/protobuf v1.5.3 // @grafana/backend-platform | ||||
| 	github.com/google/btree v1.1.2 // indirect | ||||
|  | @ -175,7 +180,7 @@ require ( | |||
| 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect | ||||
| 	github.com/hashicorp/errwrap v1.1.0 // indirect | ||||
| 	github.com/hashicorp/go-msgpack v0.5.5 // indirect | ||||
| 	github.com/hashicorp/go-multierror v1.1.1 // indirect | ||||
| 	github.com/hashicorp/go-multierror v1.1.1 // indirect; @grafana/grafana-as-code | ||||
| 	github.com/hashicorp/go-sockaddr v1.0.2 // indirect | ||||
| 	github.com/hashicorp/golang-lru v0.6.0 // indirect | ||||
| 	github.com/hashicorp/yamux v0.1.1 // indirect | ||||
|  | @ -220,7 +225,7 @@ require ( | |||
| 	golang.org/x/text v0.11.0 // @grafana/backend-platform | ||||
| 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect | ||||
| 	google.golang.org/appengine v1.6.7 // indirect | ||||
| 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect; @grafana/backend-platform | ||||
| 	google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e // indirect; @grafana/backend-platform | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
|  | @ -239,15 +244,15 @@ require ( | |||
| 	github.com/golang-migrate/migrate/v4 v4.7.0 // @grafana/backend-platform | ||||
| 	github.com/google/go-github/v45 v45.2.0 // @grafana/grafana-delivery | ||||
| 	github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad | ||||
| 	github.com/grafana/dskit v0.0.0-20230620150242-3dc2113b720d // @grafana/backend-platform | ||||
| 	github.com/grafana/dskit v0.0.0-20230706162620-5081d8ed53e6 // @grafana/backend-platform | ||||
| 	github.com/grafana/phlare/api v0.1.4-0.20230426005640-f90edba05413 // @grafana/observability-traces-and-profiling | ||||
| 	github.com/huandu/xstrings v1.3.1 // @grafana/partner-datasources | ||||
| 	github.com/jmoiron/sqlx v1.3.5 // @grafana/backend-platform | ||||
| 	github.com/matryer/is v1.4.0 // @grafana/grafana-as-code | ||||
| 	github.com/urfave/cli v1.22.12 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 // @grafana/plugins-platform-backend | ||||
| 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // @grafana/plugins-platform-backend | ||||
| 	go.opentelemetry.io/contrib/propagators/jaeger v1.15.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // @grafana/backend-platform | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // @grafana/backend-platform | ||||
| 	gocloud.dev v0.25.0 // @grafana/grafana-app-platform-squad | ||||
| ) | ||||
|  | @ -263,7 +268,7 @@ require ( | |||
| 	github.com/grafana/dataplane/sdata v0.0.6 // @grafana/observability-metrics | ||||
| 	github.com/grafana/go-mssqldb v0.9.1 // @grafana/grafana-bi-squad | ||||
| 	github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 //  @grafana/grafana-as-code | ||||
| 	github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b | ||||
| 	github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b // @grafana/observability-traces-and-profiling | ||||
| 	github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed // @grafana/grafana-as-code | ||||
| 	github.com/ory/fosite v0.44.1-0.20230317114349-45a6785cc54f // @grafana/grafana-authnz-team | ||||
| 	github.com/redis/go-redis/v9 v9.0.2 // @grafana/alerting-squad-backend | ||||
|  | @ -271,8 +276,17 @@ require ( | |||
| 	github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // @grafana/grafana-as-code | ||||
| 	go.opentelemetry.io/contrib/samplers/jaegerremote v0.9.0 // @grafana/backend-platform | ||||
| 	golang.org/x/mod v0.9.0 // @grafana/backend-platform | ||||
| 	gopkg.in/square/go-jose.v2 v2.5.2-0.20210529014059-a5c7eec3c614 // @grafana/grafana-authnz-team | ||||
| 	k8s.io/utils v0.0.0-20230308161112-d77c459e9343 // @grafana/partner-datasources | ||||
| 	gopkg.in/square/go-jose.v2 v2.6.0 // @grafana/grafana-authnz-team | ||||
| 	k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // @grafana/partner-datasources | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/grafana/grafana-apiserver v0.0.0-20230713001719-88a9ed41992d // @grafana/grafana-app-platform-squad | ||||
| 	go.opentelemetry.io/otel v1.16.0 // @grafana/backend-platform | ||||
| 	k8s.io/apiserver v0.27.1 // @grafana/grafana-app-platform-squad | ||||
| 	k8s.io/apimachinery v0.27.1 // @grafana/grafana-app-platform-squad | ||||
| 	k8s.io/client-go v0.27.1 // @grafana/grafana-app-platform-squad | ||||
| 	k8s.io/klog/v2 v2.90.1 // @grafana/grafana-app-platform-squad | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
|  | @ -281,11 +295,16 @@ require ( | |||
| 	github.com/Azure/azure-pipeline-go v0.2.3 // indirect | ||||
| 	github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect | ||||
| 	github.com/Masterminds/goutils v1.1.1 // indirect | ||||
| 	github.com/NYTimes/gziphandler v1.1.1 // indirect | ||||
| 	github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect | ||||
| 	github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect | ||||
| 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect | ||||
| 	github.com/armon/go-metrics v0.4.1 // indirect | ||||
| 	github.com/blang/semver/v4 v4.0.0 // indirect | ||||
| 	github.com/bmatcuk/doublestar v1.1.1 // indirect | ||||
| 	github.com/buildkite/yaml v2.1.0+incompatible // indirect | ||||
| 	github.com/bwmarrin/snowflake v0.3.0 // indirect | ||||
| 	github.com/centrifugal/protocol v0.10.0 // indirect | ||||
| 	github.com/cloudflare/circl v1.1.0 // indirect | ||||
| 	github.com/cockroachdb/errors v1.9.1 // indirect | ||||
| 	github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f // indirect | ||||
|  | @ -296,6 +315,7 @@ require ( | |||
| 	github.com/dave/jennifer v1.5.0 // indirect | ||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||
| 	github.com/dgraph-io/ristretto v0.1.0 // indirect | ||||
| 	github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect | ||||
| 	github.com/docker/distribution v2.8.1+incompatible // indirect | ||||
| 	github.com/docker/go-connections v0.4.0 // indirect | ||||
| 	github.com/drone-runners/drone-runner-docker v1.8.2 // indirect | ||||
|  | @ -304,9 +324,14 @@ require ( | |||
| 	github.com/drone/runner-go v1.12.0 // indirect | ||||
| 	github.com/dustin/go-humanize v1.0.1 // indirect | ||||
| 	github.com/ecordell/optgen v0.0.6 // indirect | ||||
| 	github.com/emicklei/go-restful/v3 v3.10.1 // indirect | ||||
| 	github.com/evanphx/json-patch v4.12.0+incompatible // indirect | ||||
| 	github.com/felixge/httpsnoop v1.0.3 // indirect | ||||
| 	github.com/fsnotify/fsnotify v1.6.0 // indirect | ||||
| 	github.com/getsentry/sentry-go v0.12.0 // indirect | ||||
| 	github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect | ||||
| 	github.com/google/cel-go v0.12.6 // indirect | ||||
| 	github.com/google/gnostic v0.6.9 // indirect | ||||
| 	github.com/google/go-querystring v1.1.0 // indirect | ||||
| 	github.com/google/gofuzz v1.2.0 // indirect | ||||
| 	github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect | ||||
|  | @ -318,7 +343,7 @@ require ( | |||
| 	github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect | ||||
| 	github.com/hashicorp/hcl v1.0.0 // indirect | ||||
| 	github.com/hashicorp/memberlist v0.5.0 // indirect | ||||
| 	github.com/inconshreveable/mousetrap v1.0.1 // indirect | ||||
| 	github.com/inconshreveable/mousetrap v1.1.0 // indirect | ||||
| 	github.com/invopop/yaml v0.1.0 // indirect | ||||
| 	github.com/kr/pretty v0.3.1 // indirect | ||||
| 	github.com/kr/text v0.2.0 // indirect | ||||
|  | @ -330,6 +355,8 @@ require ( | |||
| 	github.com/mitchellh/mapstructure v1.5.0 // indirect | ||||
| 	github.com/mitchellh/reflectwalk v1.0.2 // indirect | ||||
| 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect | ||||
| 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect | ||||
| 	github.com/onsi/gomega v1.27.6 // indirect | ||||
| 	github.com/opencontainers/go-digest v1.0.0 // indirect | ||||
| 	github.com/opencontainers/image-spec v1.0.3-0.20220512140940-7b36cea86235 // indirect | ||||
| 	github.com/ory/go-acc v0.2.6 // indirect | ||||
|  | @ -341,15 +368,16 @@ require ( | |||
| 	github.com/perimeterx/marshmallow v1.1.4 // indirect | ||||
| 	github.com/rivo/uniseg v0.3.4 // indirect | ||||
| 	github.com/rogpeppe/go-internal v1.10.0 // indirect | ||||
| 	github.com/rueian/rueidis v0.0.100-go1.18 // indirect | ||||
| 	github.com/rueian/rueidis v0.0.100 // indirect | ||||
| 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | ||||
| 	github.com/segmentio/asm v1.2.0 // indirect | ||||
| 	github.com/shopspring/decimal v1.2.0 // indirect | ||||
| 	github.com/spf13/afero v1.9.2 // indirect | ||||
| 	github.com/spf13/cast v1.5.0 // indirect | ||||
| 	github.com/spf13/cobra v1.6.1 // indirect | ||||
| 	github.com/spf13/cobra v1.7.0 // indirect | ||||
| 	github.com/spf13/jwalterweatherman v1.1.0 // indirect | ||||
| 	github.com/spf13/pflag v1.0.5 // indirect | ||||
| 	github.com/stoewer/go-strcase v1.2.0 // indirect | ||||
| 	github.com/subosito/gotenv v1.4.1 // indirect | ||||
| 	github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect | ||||
| 	github.com/unknwon/com v1.0.1 // indirect | ||||
|  | @ -357,13 +385,27 @@ require ( | |||
| 	github.com/weaveworks/promrus v1.2.0 // indirect | ||||
| 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect | ||||
| 	github.com/yuin/gopher-lua v1.1.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v0.37.0 // indirect | ||||
| 	go.etcd.io/etcd/api/v3 v3.5.7 // indirect | ||||
| 	go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect | ||||
| 	go.etcd.io/etcd/client/v3 v3.5.7 // indirect | ||||
| 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect | ||||
| 	go.opentelemetry.io/otel/metric v1.16.0 // indirect | ||||
| 	go.starlark.net v0.0.0-20221020143700-22309ac47eac // indirect | ||||
| 	go.uber.org/multierr v1.10.0 // indirect | ||||
| 	go.uber.org/zap v1.24.0 // indirect | ||||
| 	golang.org/x/term v0.10.0 // indirect | ||||
| 	gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect | ||||
| 	gopkg.in/inf.v0 v0.9.1 // indirect | ||||
| 	k8s.io/klog/v2 v2.90.1 // indirect | ||||
| 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect | ||||
| 	k8s.io/api v0.27.1 // indirect | ||||
| 	k8s.io/component-base v0.27.1 // indirect | ||||
| 	k8s.io/kms v0.27.1 // indirect | ||||
| 	k8s.io/kube-aggregator v0.27.1 // indirect | ||||
| 	k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect | ||||
| 	sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect | ||||
| 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect | ||||
| 	sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect | ||||
| 	sigs.k8s.io/yaml v1.3.0 // indirect | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
|  | @ -388,6 +430,7 @@ require ( | |||
| 	github.com/blugelabs/ice v1.0.0 // indirect | ||||
| 	github.com/caio/go-tdigest v3.1.0+incompatible // indirect | ||||
| 	github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2 // indirect | ||||
| 	github.com/coreos/go-semver v0.3.0 // indirect | ||||
| 	github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect | ||||
| 	github.com/docker/docker v23.0.4+incompatible // @grafana/grafana-delivery | ||||
| 	github.com/elazarl/goproxy v0.0.0-20220115173737-adb46da277ac // indirect | ||||
|  | @ -395,10 +438,10 @@ require ( | |||
| 	github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect | ||||
| 	github.com/go-git/gcfg v1.5.0 // indirect | ||||
| 	github.com/go-git/go-billy/v5 v5.3.1 // indirect | ||||
| 	github.com/go-logr/logr v1.2.4 // indirect | ||||
| 	github.com/go-logr/logr v1.2.4 // @grafana/grafana-app-platform-squad | ||||
| 	github.com/go-logr/stdr v1.2.2 // indirect | ||||
| 	github.com/google/go-github v17.0.0+incompatible // @grafana/grafana-app-platform-squad | ||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect | ||||
| 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect | ||||
| 	github.com/hmarr/codeowners v1.1.2 // @grafana/grafana-as-code | ||||
| 	github.com/imdario/mergo v0.3.13 // indirect | ||||
| 	github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect | ||||
|  | @ -415,8 +458,8 @@ require ( | |||
| 	github.com/wk8/go-ordered-map v1.0.0 // @grafana/backend-platform | ||||
| 	github.com/xanzy/ssh-agent v0.3.0 // indirect | ||||
| 	github.com/xlab/treeprint v1.1.0 // @grafana/observability-traces-and-profiling | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect | ||||
| 	go.opentelemetry.io/proto/otlp v0.19.0 // indirect | ||||
| 	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect | ||||
| 	go.opentelemetry.io/proto/otlp v0.20.0 // indirect | ||||
| 	gopkg.in/warnings.v0 v0.1.2 // indirect | ||||
| ) | ||||
| 
 | ||||
|  | @ -442,6 +485,8 @@ replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-aler | |||
| // grpc v1.46.0 removed "WithBalancerName()" API, still in use by weaveworks/commons. | ||||
| replace google.golang.org/grpc => google.golang.org/grpc v1.45.0 | ||||
| 
 | ||||
| replace google.golang.org/genproto => google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3 | ||||
| 
 | ||||
| // Use 1.10.6 of pq to avoid a change in 1.10.7 that has certificate validation issues. https://github.com/grafana/grafana/issues/65816 | ||||
| replace github.com/lib/pq => github.com/lib/pq v1.10.6 | ||||
| 
 | ||||
|  |  | |||
|  | @ -115,4 +115,5 @@ export interface FeatureToggles { | |||
|   transformationsRedesign?: boolean; | ||||
|   mlExpressions?: boolean; | ||||
|   disableTraceQLStreaming?: boolean; | ||||
|   grafanaAPIServer?: boolean; | ||||
| } | ||||
|  |  | |||
|  | @ -11,8 +11,9 @@ import ( | |||
| 	"time" | ||||
| 
 | ||||
| 	om "github.com/wk8/go-ordered-map" | ||||
| 	otlp "go.opentelemetry.io/collector/model/otlp" | ||||
| 	otelpdata "go.opentelemetry.io/collector/model/pdata" | ||||
| 	"go.opentelemetry.io/collector/model/otlp" | ||||
| 	"go.opentelemetry.io/collector/pdata/pcommon" | ||||
| 	"go.opentelemetry.io/collector/pdata/ptrace" | ||||
| ) | ||||
| 
 | ||||
| // KeyVal is an ordered map of string to interface
 | ||||
|  | @ -142,7 +143,7 @@ func (tc TraceContext) KeyVal() *KeyVal { | |||
| 
 | ||||
| // Traces wraps the otel traces model.
 | ||||
| type Traces struct { | ||||
| 	otelpdata.Traces | ||||
| 	ptrace.Traces | ||||
| } | ||||
| 
 | ||||
| // UnmarshalJSON unmarshals Traces model.
 | ||||
|  | @ -163,12 +164,12 @@ func (t Traces) MarshalJSON() ([]byte, error) { | |||
| } | ||||
| 
 | ||||
| // SpanSlice unpacks Traces entity into a slice of Spans.
 | ||||
| func (t Traces) SpanSlice() []otelpdata.Span { | ||||
| 	spans := make([]otelpdata.Span, 0) | ||||
| func (t Traces) SpanSlice() []ptrace.Span { | ||||
| 	spans := make([]ptrace.Span, 0) | ||||
| 	rss := t.ResourceSpans() | ||||
| 	for i := 0; i < rss.Len(); i++ { | ||||
| 		rs := rss.At(i) | ||||
| 		ilss := rs.InstrumentationLibrarySpans() | ||||
| 		ilss := rs.ScopeSpans() | ||||
| 		for j := 0; j < ilss.Len(); j++ { | ||||
| 			s := ilss.At(j).Spans() | ||||
| 			for si := 0; si < s.Len(); si++ { | ||||
|  | @ -180,7 +181,7 @@ func (t Traces) SpanSlice() []otelpdata.Span { | |||
| } | ||||
| 
 | ||||
| // SpanToKeyVal returns KeyVal representation of a Span.
 | ||||
| func SpanToKeyVal(s otelpdata.Span) *KeyVal { | ||||
| func SpanToKeyVal(s ptrace.Span) *KeyVal { | ||||
| 	kv := NewKeyVal() | ||||
| 	if s.StartTimestamp() > 0 { | ||||
| 		KeyValAdd(kv, "timestamp", s.StartTimestamp().AsTime().String()) | ||||
|  | @ -194,7 +195,7 @@ func SpanToKeyVal(s otelpdata.Span) *KeyVal { | |||
| 	KeyValAdd(kv, "span_kind", s.Kind().String()) | ||||
| 	KeyValAdd(kv, "name", s.Name()) | ||||
| 	KeyValAdd(kv, "parent_spanID", s.ParentSpanID().HexString()) | ||||
| 	s.Attributes().Range(func(k string, v otelpdata.AttributeValue) bool { | ||||
| 	s.Attributes().Range(func(k string, v pcommon.Value) bool { | ||||
| 		KeyValAdd(kv, "attr_"+k, fmt.Sprintf("%v", v)) | ||||
| 		return true | ||||
| 	}) | ||||
|  |  | |||
|  | @ -5,9 +5,18 @@ const ( | |||
| 	All string = "all" | ||||
| 	// BackgroundServices includes all Grafana services that run in the background
 | ||||
| 	BackgroundServices string = "background-services" | ||||
| 	// CertGenerator generates certificates for grafana-apiserver
 | ||||
| 	CertGenerator string = "cert-generator" | ||||
| 	// GrafanaAPIServer is the Kubertenes API server for Grafana Resources
 | ||||
| 	GrafanaAPIServer string = "grafana-apiserver" | ||||
| ) | ||||
| 
 | ||||
| // dependencyMap defines Module Targets => Dependencies
 | ||||
| var dependencyMap = map[string][]string{ | ||||
| 	BackgroundServices: {}, | ||||
| 
 | ||||
| 	CertGenerator:    {}, | ||||
| 	GrafanaAPIServer: {CertGenerator}, | ||||
| 
 | ||||
| 	All: {BackgroundServices}, | ||||
| } | ||||
|  |  | |||
|  | @ -3,11 +3,13 @@ package modules | |||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/grafana/dskit/modules" | ||||
| 	"github.com/grafana/dskit/services" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
| 	"github.com/grafana/grafana/pkg/services/featuremgmt" | ||||
| 	"github.com/grafana/grafana/pkg/setting" | ||||
| 	"github.com/grafana/grafana/pkg/systemd" | ||||
| ) | ||||
|  | @ -35,9 +37,14 @@ type service struct { | |||
| 	moduleManager  *modules.Manager | ||||
| 	serviceManager *services.Manager | ||||
| 	serviceMap     map[string]services.Service | ||||
| 
 | ||||
| 	features *featuremgmt.FeatureManager | ||||
| } | ||||
| 
 | ||||
| func ProvideService(cfg *setting.Cfg) *service { | ||||
| func ProvideService( | ||||
| 	cfg *setting.Cfg, | ||||
| 	features *featuremgmt.FeatureManager, | ||||
| ) *service { | ||||
| 	logger := log.New("modules") | ||||
| 
 | ||||
| 	return &service{ | ||||
|  | @ -47,6 +54,8 @@ func ProvideService(cfg *setting.Cfg) *service { | |||
| 
 | ||||
| 		moduleManager: modules.NewManager(logger), | ||||
| 		serviceMap:    map[string]services.Service{}, | ||||
| 
 | ||||
| 		features: features, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -54,6 +63,11 @@ func ProvideService(cfg *setting.Cfg) *service { | |||
| func (m *service) Init(_ context.Context) error { | ||||
| 	var err error | ||||
| 
 | ||||
| 	if err = m.processFeatureFlags(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	m.log.Debug("Initializing module manager", "targets", m.targets) | ||||
| 	for mod, targets := range dependencyMap { | ||||
| 		if err := m.moduleManager.AddDependency(mod, targets...); err != nil { | ||||
| 			return err | ||||
|  | @ -93,6 +107,7 @@ func (m *service) Run(ctx context.Context) error { | |||
| 	listener := newServiceListener(m.log, m) | ||||
| 	m.serviceManager.AddListener(listener) | ||||
| 
 | ||||
| 	m.log.Debug("Starting module service manager") | ||||
| 	// wait until a service fails or stop signal was received
 | ||||
| 	err := m.serviceManager.StartAsync(ctx) | ||||
| 	if err != nil { | ||||
|  | @ -149,3 +164,31 @@ func (m *service) RegisterInvisibleModule(name string, initFn func() (services.S | |||
| func (m *service) IsModuleEnabled(name string) bool { | ||||
| 	return stringsContain(m.targets, name) | ||||
| } | ||||
| 
 | ||||
| // processFeatureFlags adds or removes targets based on feature flags.
 | ||||
| func (m *service) processFeatureFlags() error { | ||||
| 	// add GrafanaAPIServer to targets if feature is enabled
 | ||||
| 	if m.features.IsEnabled(featuremgmt.FlagGrafanaAPIServer) { | ||||
| 		m.targets = append(m.targets, GrafanaAPIServer) | ||||
| 	} | ||||
| 
 | ||||
| 	if !m.features.IsEnabled(featuremgmt.FlagGrafanaAPIServer) { | ||||
| 		// error if GrafanaAPIServer is in targets
 | ||||
| 		for _, t := range m.targets { | ||||
| 			if t == GrafanaAPIServer { | ||||
| 				return fmt.Errorf("feature flag %s is disabled, but target %s is still enabled", featuremgmt.FlagGrafanaAPIServer, GrafanaAPIServer) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// error if GrafanaAPIServer is a dependency of a target
 | ||||
| 		for parent, targets := range dependencyMap { | ||||
| 			for _, t := range targets { | ||||
| 				if t == GrafanaAPIServer && m.IsModuleEnabled(parent) { | ||||
| 					return fmt.Errorf("feature flag %s is disabled, but target %s is enabled with dependency on %s", featuremgmt.FlagGrafanaAPIServer, parent, GrafanaAPIServer) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -3,9 +3,11 @@ package registry | |||
| import ( | ||||
| 	"github.com/grafana/dskit/services" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana-apiserver/pkg/certgenerator" | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
| 	"github.com/grafana/grafana/pkg/modules" | ||||
| 	"github.com/grafana/grafana/pkg/server/backgroundsvcs" | ||||
| 	grafanaapiserver "github.com/grafana/grafana/pkg/services/grafana-apiserver" | ||||
| ) | ||||
| 
 | ||||
| type Registry interface{} | ||||
|  | @ -17,12 +19,16 @@ type registry struct { | |||
| 
 | ||||
| func ProvideRegistry( | ||||
| 	moduleManager modules.Manager, | ||||
| 	apiServer grafanaapiserver.Service, | ||||
| 	backgroundServiceRunner *backgroundsvcs.BackgroundServiceRunner, | ||||
| 	certGenerator certgenerator.ServiceInterface, | ||||
| ) *registry { | ||||
| 	return newRegistry( | ||||
| 		log.New("modules.registry"), | ||||
| 		moduleManager, | ||||
| 		apiServer, | ||||
| 		backgroundServiceRunner, | ||||
| 		certGenerator, | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
|  | @ -41,7 +47,6 @@ func newRegistry(logger log.Logger, moduleManager modules.Manager, svcs ...servi | |||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	// Register module targets
 | ||||
| 	logger.Debug("Registering module", "name", modules.All) | ||||
| 	r.moduleManager.RegisterModule(modules.All, nil) | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,31 +9,8 @@ import ( | |||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
| 	"github.com/grafana/grafana/pkg/modules" | ||||
| 	"github.com/grafana/grafana/pkg/server/backgroundsvcs" | ||||
| ) | ||||
| 
 | ||||
| func TestProvideRegistry(t *testing.T) { | ||||
| 	var registeredInvisibleModules []string | ||||
| 	var registeredModules []string | ||||
| 
 | ||||
| 	moduleManager := &modules.MockModuleManager{ | ||||
| 		RegisterModuleFunc: func(name string, initFn func() (services.Service, error)) { | ||||
| 			registeredModules = append(registeredModules, name) | ||||
| 		}, | ||||
| 		RegisterInvisibleModuleFunc: func(name string, initFn func() (services.Service, error)) { | ||||
| 			registeredInvisibleModules = append(registeredInvisibleModules, name) | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	svcRegistry := backgroundsvcs.NewBackgroundServiceRegistry() | ||||
| 	svcRunner := backgroundsvcs.ProvideBackgroundServiceRunner(svcRegistry) | ||||
| 
 | ||||
| 	r := ProvideRegistry(moduleManager, svcRunner) | ||||
| 	require.NotNil(t, r) | ||||
| 	require.Equal(t, []string{modules.BackgroundServices}, registeredInvisibleModules) | ||||
| 	require.Equal(t, []string{modules.All}, registeredModules) | ||||
| } | ||||
| 
 | ||||
| func TestNewRegistry(t *testing.T) { | ||||
| 	var registeredInvisibleModules []string | ||||
| 	var registeredModules []string | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/services/apikey/apikeyimpl" | ||||
| 	"github.com/grafana/grafana/pkg/services/auth/jwt" | ||||
| 	"github.com/grafana/grafana/pkg/services/authn/authnimpl" | ||||
| 	"github.com/grafana/grafana/pkg/services/certgenerator" | ||||
| 	"github.com/grafana/grafana/pkg/services/cleanup" | ||||
| 	"github.com/grafana/grafana/pkg/services/contexthandler" | ||||
| 	"github.com/grafana/grafana/pkg/services/contexthandler/authproxy" | ||||
|  | @ -64,6 +65,7 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/services/featuremgmt" | ||||
| 	"github.com/grafana/grafana/pkg/services/folder" | ||||
| 	"github.com/grafana/grafana/pkg/services/folder/folderimpl" | ||||
| 	"github.com/grafana/grafana/pkg/services/grafana-apiserver" | ||||
| 	"github.com/grafana/grafana/pkg/services/grpcserver" | ||||
| 	grpccontext "github.com/grafana/grafana/pkg/services/grpcserver/context" | ||||
| 	"github.com/grafana/grafana/pkg/services/grpcserver/interceptors" | ||||
|  | @ -204,6 +206,7 @@ var wireBasicSet = wire.NewSet( | |||
| 	wire.Bind(new(httpclient.Provider), new(*sdkhttpclient.Provider)), | ||||
| 	serverlock.ProvideService, | ||||
| 	annotationsimpl.ProvideCleanupService, | ||||
| 	certgenerator.WireSet, | ||||
| 	wire.Bind(new(annotations.Cleaner), new(*annotationsimpl.CleanupServiceImpl)), | ||||
| 	cleanup.ProvideService, | ||||
| 	shorturlimpl.ProvideService, | ||||
|  | @ -355,6 +358,7 @@ var wireBasicSet = wire.NewSet( | |||
| 	wire.Bind(new(tag.Service), new(*tagimpl.Service)), | ||||
| 	authnimpl.ProvideService, | ||||
| 	supportbundlesimpl.ProvideService, | ||||
| 	grafanaapiserver.WireSet, | ||||
| 	oasimpl.ProvideService, | ||||
| 	wire.Bind(new(oauthserver.OAuth2Server), new(*oasimpl.OAuth2ServiceImpl)), | ||||
| 	loggermw.Provide, | ||||
|  |  | |||
|  | @ -0,0 +1,14 @@ | |||
| package certgenerator | ||||
| 
 | ||||
| import ( | ||||
| 	"path/filepath" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/modules" | ||||
| 	"github.com/grafana/grafana/pkg/setting" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana-apiserver/pkg/certgenerator" | ||||
| ) | ||||
| 
 | ||||
| func ProvideService(cfg *setting.Cfg) (*certgenerator.Service, error) { | ||||
| 	return certgenerator.CreateService(modules.CertGenerator, filepath.Join(cfg.DataPath, "k8s")) | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| package certgenerator | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/google/wire" | ||||
| 	"github.com/grafana/grafana-apiserver/pkg/certgenerator" | ||||
| ) | ||||
| 
 | ||||
| var WireSet = wire.NewSet( | ||||
| 	ProvideService, | ||||
| 	wire.Bind(new(certgenerator.ServiceInterface), new(*certgenerator.Service)), | ||||
| ) | ||||
|  | @ -115,3 +115,9 @@ func (mw mockWriter) Before(web.BeforeFunc) {} | |||
| func (mw mockWriter) Push(target string, opts *http.PushOptions) error { | ||||
| 	return nil | ||||
| } | ||||
| func (mw mockWriter) CloseNotify() <-chan bool { | ||||
| 	return make(<-chan bool) | ||||
| } | ||||
| func (mw mockWriter) Unwrap() http.ResponseWriter { | ||||
| 	return mw | ||||
| } | ||||
|  |  | |||
|  | @ -661,5 +661,12 @@ var ( | |||
| 			FrontendOnly: true, | ||||
| 			Owner:        grafanaObservabilityTracesAndProfilingSquad, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name:         "grafanaAPIServer", | ||||
| 			Description:  "Enable Kubernetes API Server for Grafana resources", | ||||
| 			Stage:        FeatureStageExperimental, | ||||
| 			FrontendOnly: false, | ||||
| 			Owner:        grafanaAppPlatformSquad, | ||||
| 		}, | ||||
| 	} | ||||
| ) | ||||
|  |  | |||
|  | @ -96,3 +96,4 @@ awsDatasourcesTempCredentials,experimental,@grafana/aws-datasources,false,false, | |||
| transformationsRedesign,experimental,@grafana/observability-metrics,false,false,false,true | ||||
| mlExpressions,experimental,@grafana/alerting-squad,false,false,false,false | ||||
| disableTraceQLStreaming,experimental,@grafana/observability-traces-and-profiling,false,false,false,true | ||||
| grafanaAPIServer,experimental,@grafana/grafana-app-platform-squad,false,false,false,false | ||||
|  |  | |||
| 
 | 
|  | @ -394,4 +394,8 @@ const ( | |||
| 	// FlagDisableTraceQLStreaming
 | ||||
| 	// Disables the option to stream the response of TraceQL queries of the Tempo data source
 | ||||
| 	FlagDisableTraceQLStreaming = "disableTraceQLStreaming" | ||||
| 
 | ||||
| 	// FlagGrafanaAPIServer
 | ||||
| 	// Enable Kubernetes API Server for Grafana resources
 | ||||
| 	FlagGrafanaAPIServer = "grafanaAPIServer" | ||||
| ) | ||||
|  |  | |||
|  | @ -0,0 +1,50 @@ | |||
| package grafanaapiserver | ||||
| 
 | ||||
| import ( | ||||
| 	"cuelang.org/go/pkg/strings" | ||||
| 	"github.com/go-logr/logr" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
| ) | ||||
| 
 | ||||
| var _ logr.LogSink = (*logAdapter)(nil) | ||||
| 
 | ||||
| type logAdapter struct { | ||||
| 	log log.Logger | ||||
| } | ||||
| 
 | ||||
| func newLogAdapter() *logAdapter { | ||||
| 	return &logAdapter{log: log.New("k8s.apiserver")} | ||||
| } | ||||
| 
 | ||||
| func (l *logAdapter) WithName(name string) logr.LogSink { | ||||
| 	l.log = l.log.New("name", name) | ||||
| 	return l | ||||
| } | ||||
| 
 | ||||
| func (l *logAdapter) WithValues(keysAndValues ...interface{}) logr.LogSink { | ||||
| 	l.log = l.log.New(keysAndValues...) | ||||
| 	return l | ||||
| } | ||||
| 
 | ||||
| func (l *logAdapter) Init(_ logr.RuntimeInfo) { | ||||
| 	// TODO: shrug emoji
 | ||||
| } | ||||
| 
 | ||||
| func (l *logAdapter) Enabled(level int) bool { | ||||
| 	return level <= 5 | ||||
| } | ||||
| 
 | ||||
| func (l *logAdapter) Info(level int, msg string, keysAndValues ...interface{}) { | ||||
| 	msg = strings.TrimSpace(msg) | ||||
| 	if level < 1 { | ||||
| 		l.log.Info(msg, keysAndValues...) | ||||
| 		return | ||||
| 	} | ||||
| 	l.log.Debug(msg, keysAndValues...) | ||||
| } | ||||
| 
 | ||||
| func (l *logAdapter) Error(err error, msg string, keysAndValues ...interface{}) { | ||||
| 	msg = strings.TrimSpace(msg) | ||||
| 	l.log.Error(msg, keysAndValues...) | ||||
| } | ||||
|  | @ -0,0 +1,248 @@ | |||
| package grafanaapiserver | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/x509" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"cuelang.org/go/pkg/strings" | ||||
| 	"github.com/go-logr/logr" | ||||
| 	"github.com/grafana/dskit/services" | ||||
| 	grafanaapiserveroptions "github.com/grafana/grafana-apiserver/pkg/cmd/server/options" | ||||
| 	"k8s.io/apiserver/pkg/authentication/authenticator" | ||||
| 	"k8s.io/apiserver/pkg/authentication/request/headerrequest" | ||||
| 	"k8s.io/apiserver/pkg/authentication/user" | ||||
| 	"k8s.io/apiserver/pkg/endpoints/responsewriter" | ||||
| 	genericapiserver "k8s.io/apiserver/pkg/server" | ||||
| 	"k8s.io/apiserver/pkg/server/options" | ||||
| 	"k8s.io/client-go/rest" | ||||
| 	"k8s.io/client-go/tools/clientcmd" | ||||
| 	clientcmdapi "k8s.io/client-go/tools/clientcmd/api" | ||||
| 	"k8s.io/klog/v2" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana-apiserver/pkg/certgenerator" | ||||
| 	"github.com/grafana/grafana/pkg/api/routing" | ||||
| 	"github.com/grafana/grafana/pkg/infra/appcontext" | ||||
| 	"github.com/grafana/grafana/pkg/middleware" | ||||
| 	"github.com/grafana/grafana/pkg/modules" | ||||
| 	contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" | ||||
| 	"github.com/grafana/grafana/pkg/setting" | ||||
| 	"github.com/grafana/grafana/pkg/web" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	DefaultAPIServerHost = "https://" + certgenerator.DefaultAPIServerIp + ":6443" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	_ Service            = (*service)(nil) | ||||
| 	_ RestConfigProvider = (*service)(nil) | ||||
| ) | ||||
| 
 | ||||
| type Service interface { | ||||
| 	services.NamedService | ||||
| } | ||||
| 
 | ||||
| type RestConfigProvider interface { | ||||
| 	GetRestConfig() *rest.Config | ||||
| } | ||||
| 
 | ||||
| type service struct { | ||||
| 	*services.BasicService | ||||
| 
 | ||||
| 	restConfig *rest.Config | ||||
| 	rr         routing.RouteRegister | ||||
| 
 | ||||
| 	handler   web.Handler | ||||
| 	dataPath  string | ||||
| 	stopCh    chan struct{} | ||||
| 	stoppedCh chan error | ||||
| } | ||||
| 
 | ||||
| func ProvideService(cfg *setting.Cfg, rr routing.RouteRegister) (*service, error) { | ||||
| 	s := &service{ | ||||
| 		rr:       rr, | ||||
| 		dataPath: path.Join(cfg.DataPath, "k8s"), | ||||
| 		stopCh:   make(chan struct{}), | ||||
| 	} | ||||
| 
 | ||||
| 	s.BasicService = services.NewBasicService(s.start, s.running, nil).WithName(modules.GrafanaAPIServer) | ||||
| 
 | ||||
| 	s.rr.Group("/k8s", func(k8sRoute routing.RouteRegister) { | ||||
| 		handler := func(c *contextmodel.ReqContext) { | ||||
| 			if s.handler == nil { | ||||
| 				c.Resp.WriteHeader(404) | ||||
| 				_, _ = c.Resp.Write([]byte("Not found")) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			if handle, ok := s.handler.(func(c *contextmodel.ReqContext)); ok { | ||||
| 				handle(c) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		k8sRoute.Any("/", middleware.ReqSignedIn, handler) | ||||
| 		k8sRoute.Any("/*", middleware.ReqSignedIn, handler) | ||||
| 	}) | ||||
| 
 | ||||
| 	return s, nil | ||||
| } | ||||
| 
 | ||||
| func (s *service) GetRestConfig() *rest.Config { | ||||
| 	return s.restConfig | ||||
| } | ||||
| 
 | ||||
| func (s *service) start(ctx context.Context) error { | ||||
| 	logger := logr.New(newLogAdapter()) | ||||
| 	logger.V(9) | ||||
| 	klog.SetLoggerWithOptions(logger, klog.ContextualLogger(true)) | ||||
| 
 | ||||
| 	o := grafanaapiserveroptions.NewGrafanaAPIServerOptions(os.Stdout, os.Stderr) | ||||
| 	o.RecommendedOptions.SecureServing.BindPort = 6443 | ||||
| 	o.RecommendedOptions.Authentication.RemoteKubeConfigFileOptional = true | ||||
| 	o.RecommendedOptions.Authorization.RemoteKubeConfigFileOptional = true | ||||
| 	o.RecommendedOptions.Authorization.AlwaysAllowPaths = []string{"*"} | ||||
| 	o.RecommendedOptions.Authorization.AlwaysAllowGroups = []string{user.SystemPrivilegedGroup, "grafana"} | ||||
| 	o.RecommendedOptions.Etcd = nil | ||||
| 	// TODO: setting CoreAPI to nil currently segfaults in grafana-apiserver
 | ||||
| 	o.RecommendedOptions.CoreAPI = nil | ||||
| 
 | ||||
| 	// Get the util to get the paths to pre-generated certs
 | ||||
| 	certUtil := certgenerator.CertUtil{ | ||||
| 		K8sDataPath: s.dataPath, | ||||
| 	} | ||||
| 
 | ||||
| 	o.RecommendedOptions.SecureServing.BindAddress = net.ParseIP(certgenerator.DefaultAPIServerIp) | ||||
| 	o.RecommendedOptions.SecureServing.ServerCert.CertKey = options.CertKey{ | ||||
| 		CertFile: certUtil.APIServerCertFile(), | ||||
| 		KeyFile:  certUtil.APIServerKeyFile(), | ||||
| 	} | ||||
| 
 | ||||
| 	if err := o.Complete(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := o.Validate(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	serverConfig, err := o.Config() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	rootCert, err := certUtil.GetK8sCACert() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	authenticator, err := newAuthenticator(rootCert) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	serverConfig.GenericConfig.Authentication.Authenticator = authenticator | ||||
| 
 | ||||
| 	server, err := serverConfig.Complete().New(genericapiserver.NewEmptyDelegate()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	s.restConfig = server.GenericAPIServer.LoopbackClientConfig | ||||
| 	err = s.writeKubeConfiguration(s.restConfig) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	prepared := server.GenericAPIServer.PrepareRun() | ||||
| 
 | ||||
| 	s.handler = func(c *contextmodel.ReqContext) { | ||||
| 		req := c.Req | ||||
| 		req.URL.Path = strings.TrimPrefix(req.URL.Path, "/k8s") | ||||
| 		if req.URL.Path == "" { | ||||
| 			req.URL.Path = "/" | ||||
| 		} | ||||
| 		ctx := req.Context() | ||||
| 		signedInUser := appcontext.MustUser(ctx) | ||||
| 
 | ||||
| 		req.Header.Set("X-Remote-User", strconv.FormatInt(signedInUser.UserID, 10)) | ||||
| 		req.Header.Set("X-Remote-Group", "grafana") | ||||
| 		req.Header.Set("X-Remote-Extra-token-name", signedInUser.Name) | ||||
| 		req.Header.Set("X-Remote-Extra-org-role", string(signedInUser.OrgRole)) | ||||
| 		req.Header.Set("X-Remote-Extra-org-id", strconv.FormatInt(signedInUser.OrgID, 10)) | ||||
| 		req.Header.Set("X-Remote-Extra-user-id", strconv.FormatInt(signedInUser.UserID, 10)) | ||||
| 
 | ||||
| 		resp := responsewriter.WrapForHTTP1Or2(c.Resp) | ||||
| 		prepared.GenericAPIServer.Handler.ServeHTTP(resp, req) | ||||
| 	} | ||||
| 
 | ||||
| 	go func() { | ||||
| 		s.stoppedCh <- prepared.Run(s.stopCh) | ||||
| 	}() | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *service) running(ctx context.Context) error { | ||||
| 	select { | ||||
| 	case err := <-s.stoppedCh: | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	case <-ctx.Done(): | ||||
| 		close(s.stopCh) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *service) writeKubeConfiguration(restConfig *rest.Config) error { | ||||
| 	clusters := make(map[string]*clientcmdapi.Cluster) | ||||
| 	clusters["default-cluster"] = &clientcmdapi.Cluster{ | ||||
| 		Server:                restConfig.Host, | ||||
| 		InsecureSkipTLSVerify: true, | ||||
| 	} | ||||
| 
 | ||||
| 	contexts := make(map[string]*clientcmdapi.Context) | ||||
| 	contexts["default-context"] = &clientcmdapi.Context{ | ||||
| 		Cluster:   "default-cluster", | ||||
| 		Namespace: "default", | ||||
| 		AuthInfo:  "default", | ||||
| 	} | ||||
| 
 | ||||
| 	authinfos := make(map[string]*clientcmdapi.AuthInfo) | ||||
| 	authinfos["default"] = &clientcmdapi.AuthInfo{ | ||||
| 		Token: restConfig.BearerToken, | ||||
| 	} | ||||
| 
 | ||||
| 	clientConfig := clientcmdapi.Config{ | ||||
| 		Kind:           "Config", | ||||
| 		APIVersion:     "v1", | ||||
| 		Clusters:       clusters, | ||||
| 		Contexts:       contexts, | ||||
| 		CurrentContext: "default-context", | ||||
| 		AuthInfos:      authinfos, | ||||
| 	} | ||||
| 	return clientcmd.WriteToFile(clientConfig, path.Join(s.dataPath, "grafana.kubeconfig")) | ||||
| } | ||||
| 
 | ||||
| func newAuthenticator(cert *x509.Certificate) (authenticator.Request, error) { | ||||
| 	reqHeaderOptions := options.RequestHeaderAuthenticationOptions{ | ||||
| 		UsernameHeaders:     []string{"X-Remote-User"}, | ||||
| 		GroupHeaders:        []string{"X-Remote-Group"}, | ||||
| 		ExtraHeaderPrefixes: []string{"X-Remote-Extra-"}, | ||||
| 	} | ||||
| 
 | ||||
| 	requestHeaderAuthenticator, err := headerrequest.New( | ||||
| 		reqHeaderOptions.UsernameHeaders, | ||||
| 		reqHeaderOptions.GroupHeaders, | ||||
| 		reqHeaderOptions.ExtraHeaderPrefixes, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return requestHeaderAuthenticator, nil | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| package grafanaapiserver | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/google/wire" | ||||
| ) | ||||
| 
 | ||||
| var WireSet = wire.NewSet( | ||||
| 	ProvideService, | ||||
| 	wire.Bind(new(Service), new(*service)), | ||||
| 	wire.Bind(new(RestConfigProvider), new(*service)), | ||||
| ) | ||||
|  | @ -15,7 +15,7 @@ | |||
| package tempo | ||||
| 
 | ||||
| import ( | ||||
| 	"go.opentelemetry.io/collector/model/pdata" | ||||
| 	"go.opentelemetry.io/collector/pdata/ptrace" | ||||
| ) | ||||
| 
 | ||||
| // Some of the keys used to represent OTLP constructs as tags or annotations in other formats.
 | ||||
|  | @ -55,9 +55,9 @@ const ( | |||
| 
 | ||||
| // StatusCodeFromHTTP takes an HTTP status code and return the appropriate OpenTelemetry status code
 | ||||
| // See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#status
 | ||||
| func StatusCodeFromHTTP(httpStatusCode int) pdata.StatusCode { | ||||
| func StatusCodeFromHTTP(httpStatusCode int) ptrace.StatusCode { | ||||
| 	if httpStatusCode >= 100 && httpStatusCode < 399 { | ||||
| 		return pdata.StatusCodeUnset | ||||
| 		return ptrace.StatusCodeUnset | ||||
| 	} | ||||
| 	return pdata.StatusCodeError | ||||
| 	return ptrace.StatusCodeError | ||||
| } | ||||
|  |  | |||
|  | @ -7,7 +7,10 @@ import ( | |||
| 
 | ||||
| 	"github.com/grafana/grafana-plugin-sdk-go/data" | ||||
| 	"go.opentelemetry.io/collector/model/pdata" | ||||
| 	semconv "go.opentelemetry.io/collector/model/semconv/v1.8.0" | ||||
| 	"go.opentelemetry.io/collector/pdata/pcommon" | ||||
| 	"go.opentelemetry.io/collector/pdata/ptrace" | ||||
| 	"go.opentelemetry.io/otel/attribute" | ||||
| 	semconv "go.opentelemetry.io/otel/semconv/v1.15.0" | ||||
| ) | ||||
| 
 | ||||
| type KeyValue struct { | ||||
|  | @ -27,7 +30,7 @@ type TraceReference struct { | |||
| 	Tags    []*KeyValue `json:"tags"` | ||||
| } | ||||
| 
 | ||||
| func TraceToFrame(td pdata.Traces) (*data.Frame, error) { | ||||
| func TraceToFrame(td ptrace.Traces) (*data.Frame, error) { | ||||
| 	// In open telemetry format the spans are grouped first by resource/service they originated in and inside that
 | ||||
| 	// resource they are grouped by the instrumentation library which created them.
 | ||||
| 
 | ||||
|  | @ -80,9 +83,9 @@ func TraceToFrame(td pdata.Traces) (*data.Frame, error) { | |||
| } | ||||
| 
 | ||||
| // resourceSpansToRows processes all the spans for a particular resource/service
 | ||||
| func resourceSpansToRows(rs pdata.ResourceSpans) ([][]interface{}, error) { | ||||
| func resourceSpansToRows(rs ptrace.ResourceSpans) ([][]interface{}, error) { | ||||
| 	resource := rs.Resource() | ||||
| 	ilss := rs.InstrumentationLibrarySpans() | ||||
| 	ilss := rs.ScopeSpans() | ||||
| 
 | ||||
| 	if resource.Attributes().Len() == 0 || ilss.Len() == 0 { | ||||
| 		return [][]interface{}{}, nil | ||||
|  | @ -100,7 +103,7 @@ func resourceSpansToRows(rs pdata.ResourceSpans) ([][]interface{}, error) { | |||
| 
 | ||||
| 		for j := 0; j < spans.Len(); j++ { | ||||
| 			span := spans.At(j) | ||||
| 			row, err := spanToSpanRow(span, ils.InstrumentationLibrary(), resource) | ||||
| 			row, err := spanToSpanRow(span, ils.Scope(), resource) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | @ -113,7 +116,7 @@ func resourceSpansToRows(rs pdata.ResourceSpans) ([][]interface{}, error) { | |||
| 	return rows, nil | ||||
| } | ||||
| 
 | ||||
| func spanToSpanRow(span pdata.Span, libraryTags pdata.InstrumentationLibrary, resource pdata.Resource) ([]interface{}, error) { | ||||
| func spanToSpanRow(span ptrace.Span, libraryTags pcommon.InstrumentationScope, resource pcommon.Resource) ([]interface{}, error) { | ||||
| 	// If the id representation changed from hexstring to something else we need to change the transformBase64IDToHexString in the frontend code
 | ||||
| 	traceID := span.TraceID().HexString() | ||||
| 	traceID = strings.TrimPrefix(traceID, strings.Repeat("0", 16)) | ||||
|  | @ -175,7 +178,7 @@ func spanToSpanRow(span pdata.Span, libraryTags pdata.InstrumentationLibrary, re | |||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func resourceToProcess(resource pdata.Resource) (string, []*KeyValue) { | ||||
| func resourceToProcess(resource pcommon.Resource) (string, []*KeyValue) { | ||||
| 	attrs := resource.Attributes() | ||||
| 	serviceName := ResourceNoServiceName | ||||
| 	if attrs.Len() == 0 { | ||||
|  | @ -183,8 +186,8 @@ func resourceToProcess(resource pdata.Resource) (string, []*KeyValue) { | |||
| 	} | ||||
| 
 | ||||
| 	tags := make([]*KeyValue, 0, attrs.Len()-1) | ||||
| 	attrs.Range(func(key string, attr pdata.AttributeValue) bool { | ||||
| 		if key == semconv.AttributeServiceName { | ||||
| 	attrs.Range(func(key string, attr pcommon.Value) bool { | ||||
| 		if attribute.Key(key) == semconv.ServiceNameKey { | ||||
| 			serviceName = attr.StringVal() | ||||
| 		} | ||||
| 		tags = append(tags, &KeyValue{Key: key, Value: getAttributeVal(attr)}) | ||||
|  | @ -194,44 +197,44 @@ func resourceToProcess(resource pdata.Resource) (string, []*KeyValue) { | |||
| 	return serviceName, tags | ||||
| } | ||||
| 
 | ||||
| func getAttributeVal(attr pdata.AttributeValue) interface{} { | ||||
| func getAttributeVal(attr pcommon.Value) interface{} { | ||||
| 	switch attr.Type() { | ||||
| 	case pdata.AttributeValueTypeString: | ||||
| 	case pcommon.ValueTypeString: | ||||
| 		return attr.StringVal() | ||||
| 	case pdata.AttributeValueTypeInt: | ||||
| 	case pcommon.ValueTypeInt: | ||||
| 		return attr.IntVal() | ||||
| 	case pdata.AttributeValueTypeBool: | ||||
| 	case pcommon.ValueTypeBool: | ||||
| 		return attr.BoolVal() | ||||
| 	case pdata.AttributeValueTypeDouble: | ||||
| 	case pcommon.ValueTypeDouble: | ||||
| 		return attr.DoubleVal() | ||||
| 	case pdata.AttributeValueTypeMap, pdata.AttributeValueTypeArray: | ||||
| 	case pcommon.ValueTypeMap, pcommon.ValueTypeSlice: | ||||
| 		return attr.AsString() | ||||
| 	default: | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func getSpanTags(span pdata.Span) []*KeyValue { | ||||
| func getSpanTags(span ptrace.Span) []*KeyValue { | ||||
| 	var tags []*KeyValue | ||||
| 	span.Attributes().Range(func(key string, attr pdata.AttributeValue) bool { | ||||
| 	span.Attributes().Range(func(key string, attr pcommon.Value) bool { | ||||
| 		tags = append(tags, &KeyValue{Key: key, Value: getAttributeVal(attr)}) | ||||
| 		return true | ||||
| 	}) | ||||
| 	return tags | ||||
| } | ||||
| 
 | ||||
| func getSpanKind(spanKind pdata.SpanKind) string { | ||||
| func getSpanKind(spanKind ptrace.SpanKind) string { | ||||
| 	var tagStr string | ||||
| 	switch spanKind { | ||||
| 	case pdata.SpanKindClient: | ||||
| 	case ptrace.SpanKindClient: | ||||
| 		tagStr = string(OpenTracingSpanKindClient) | ||||
| 	case pdata.SpanKindServer: | ||||
| 	case ptrace.SpanKindServer: | ||||
| 		tagStr = string(OpenTracingSpanKindServer) | ||||
| 	case pdata.SpanKindProducer: | ||||
| 	case ptrace.SpanKindProducer: | ||||
| 		tagStr = string(OpenTracingSpanKindProducer) | ||||
| 	case pdata.SpanKindConsumer: | ||||
| 	case ptrace.SpanKindConsumer: | ||||
| 		tagStr = string(OpenTracingSpanKindConsumer) | ||||
| 	case pdata.SpanKindInternal: | ||||
| 	case ptrace.SpanKindInternal: | ||||
| 		tagStr = string(OpenTracingSpanKindInternal) | ||||
| 	default: | ||||
| 		return "" | ||||
|  | @ -240,14 +243,11 @@ func getSpanKind(spanKind pdata.SpanKind) string { | |||
| 	return tagStr | ||||
| } | ||||
| 
 | ||||
| func getTraceState(traceState pdata.TraceState) string { | ||||
| 	if traceState != pdata.TraceStateEmpty { | ||||
| 		return string(traceState) | ||||
| 	} | ||||
| 	return "" | ||||
| func getTraceState(traceState ptrace.TraceState) string { | ||||
| 	return string(traceState) | ||||
| } | ||||
| 
 | ||||
| func spanEventsToLogs(events pdata.SpanEventSlice) []*TraceLog { | ||||
| func spanEventsToLogs(events ptrace.SpanEventSlice) []*TraceLog { | ||||
| 	if events.Len() == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | @ -259,10 +259,10 @@ func spanEventsToLogs(events pdata.SpanEventSlice) []*TraceLog { | |||
| 		if event.Name() != "" { | ||||
| 			fields = append(fields, &KeyValue{ | ||||
| 				Key:   TagMessage, | ||||
| 				Value: event.Name(), | ||||
| 				Value: attribute.StringValue(event.Name()), | ||||
| 			}) | ||||
| 		} | ||||
| 		event.Attributes().Range(func(key string, attr pdata.AttributeValue) bool { | ||||
| 		event.Attributes().Range(func(key string, attr pcommon.Value) bool { | ||||
| 			fields = append(fields, &KeyValue{Key: key, Value: getAttributeVal(attr)}) | ||||
| 			return true | ||||
| 		}) | ||||
|  | @ -290,7 +290,7 @@ func spanLinksToReferences(links pdata.SpanLinkSlice) []*TraceReference { | |||
| 		spanId := link.SpanID().HexString() | ||||
| 
 | ||||
| 		tags := make([]*KeyValue, 0, link.Attributes().Len()) | ||||
| 		link.Attributes().Range(func(key string, attr pdata.AttributeValue) bool { | ||||
| 		link.Attributes().Range(func(key string, attr pcommon.Value) bool { | ||||
| 			tags = append(tags, &KeyValue{Key: key, Value: getAttributeVal(attr)}) | ||||
| 			return true | ||||
| 		}) | ||||
|  |  | |||
|  | @ -5,15 +5,17 @@ import ( | |||
| 	"os" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"go.opentelemetry.io/collector/pdata/pcommon" | ||||
| 	"go.opentelemetry.io/collector/pdata/ptrace" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana-plugin-sdk-go/data" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	otlp "go.opentelemetry.io/collector/model/otlp" | ||||
| 	"go.opentelemetry.io/collector/model/pdata" | ||||
| 	"go.opentelemetry.io/collector/model/otlp" | ||||
| ) | ||||
| 
 | ||||
| func TestTraceToFrame(t *testing.T) { | ||||
| 	t.Run("should transform tempo protobuf response into dataframe", func(t *testing.T) { | ||||
| 		// For what ever reason you cannot easily create pdata.Traces for the TraceToFrame from something more readable
 | ||||
| 		// For what ever reason you cannot easily create ptrace.Traces for the TraceToFrame from something more readable
 | ||||
| 		// like json. You could tediously create the structures manually using all the setters for everything or use
 | ||||
| 		// https://github.com/grafana/tempo/tree/master/pkg/tempopb to create the protobuf structs from something like
 | ||||
| 		// json. At the moment just saving some real tempo proto response into file and loading was the easiest and
 | ||||
|  | @ -60,14 +62,14 @@ func TestTraceToFrame(t *testing.T) { | |||
| 		require.NoError(t, err) | ||||
| 
 | ||||
| 		var index int | ||||
| 		otTrace.ResourceSpans().RemoveIf(func(rsp pdata.ResourceSpans) bool { | ||||
| 			rsp.InstrumentationLibrarySpans().RemoveIf(func(sp pdata.InstrumentationLibrarySpans) bool { | ||||
| 				sp.Spans().RemoveIf(func(span pdata.Span) bool { | ||||
| 		otTrace.ResourceSpans().RemoveIf(func(rsp ptrace.ResourceSpans) bool { | ||||
| 			rsp.ScopeSpans().RemoveIf(func(sp ptrace.ScopeSpans) bool { | ||||
| 				sp.Spans().RemoveIf(func(span ptrace.Span) bool { | ||||
| 					if index == 0 { | ||||
| 						span.SetTraceID(pdata.NewTraceID([16]byte{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7})) | ||||
| 						span.SetTraceID(pcommon.NewTraceID([16]byte{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7})) | ||||
| 					} | ||||
| 					if index == 1 { | ||||
| 						span.SetTraceID(pdata.NewTraceID([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7})) | ||||
| 						span.SetTraceID(pcommon.NewTraceID([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7})) | ||||
| 					} | ||||
| 					index++ | ||||
| 					return false | ||||
|  |  | |||
|  | @ -19,11 +19,15 @@ import ( | |||
| 	"errors" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"k8s.io/apiserver/pkg/endpoints/responsewriter" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	_ http.ResponseWriter = &responseWriter{} | ||||
| 	_ http.Hijacker       = &responseWriter{} | ||||
| 	_ http.ResponseWriter                  = &responseWriter{} | ||||
| 	_ http.Hijacker                        = &responseWriter{} | ||||
| 	_ responsewriter.CloseNotifierFlusher  = &responseWriter{} | ||||
| 	_ responsewriter.UserProvidedDecorator = &responseWriter{} | ||||
| ) | ||||
| 
 | ||||
| // ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about
 | ||||
|  | @ -41,6 +45,10 @@ type ResponseWriter interface { | |||
| 	// Before allows for a function to be called before the ResponseWriter has been written to. This is
 | ||||
| 	// useful for setting headers or any other operations that must happen before a response has been written.
 | ||||
| 	Before(BeforeFunc) | ||||
| 
 | ||||
| 	// Needed to support https://pkg.go.dev/k8s.io/apiserver@v0.27.2/pkg/endpoints/responsewriter#WrapForHTTP1Or2
 | ||||
| 	http.CloseNotifier | ||||
| 	Unwrap() http.ResponseWriter | ||||
| } | ||||
| 
 | ||||
| // BeforeFunc is a function that is called before the ResponseWriter has been written to.
 | ||||
|  | @ -139,3 +147,16 @@ func (rw *responseWriter) Flush() { | |||
| 		flusher.Flush() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (rw *responseWriter) Unwrap() http.ResponseWriter { | ||||
| 	return rw.ResponseWriter | ||||
| } | ||||
| 
 | ||||
| func (rw *responseWriter) CloseNotify() <-chan bool { | ||||
| 	notifier, ok := rw.ResponseWriter.(http.CloseNotifier) | ||||
| 	if ok { | ||||
| 		return notifier.CloseNotify() | ||||
| 	} | ||||
| 	// TODO: this is probably not the right thing to do here
 | ||||
| 	return make(<-chan bool) | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue