From 1b0e6b5c09b2d464e3a4b45e556a98b369dbb593 Mon Sep 17 00:00:00 2001 From: Todd Treece <360020+toddtreece@users.noreply.github.com> Date: Tue, 13 Aug 2024 15:28:17 -0400 Subject: [PATCH] K8s: Data Plane Aggregator (#91228) --- .github/CODEOWNERS | 1 + .golangci.toml | 16 +- go.work | 1 + go.work.sum | 9 +- pkg/aggregator/apis/aggregation/doc.go | 4 + .../apis/aggregation/install/install.go | 16 + pkg/aggregator/apis/aggregation/register.go | 40 ++ pkg/aggregator/apis/aggregation/types.go | 136 +++++ .../apis/aggregation/v0alpha1/doc.go | 7 + .../aggregation/v0alpha1/helper/helper.go | 54 ++ .../apis/aggregation/v0alpha1/register.go | 52 ++ .../apis/aggregation/v0alpha1/types.go | 136 +++++ .../v0alpha1/zz_generated.conversion.go | 270 +++++++++ .../v0alpha1/zz_generated.deepcopy.go | 176 ++++++ .../v0alpha1/zz_generated.defaults.go | 19 + .../v0alpha1/zz_generated.openapi.go | 357 ++++++++++++ .../apis/aggregation/zz_generated.deepcopy.go | 176 ++++++ pkg/aggregator/apiserver/apiserver.go | 207 +++++++ .../apiserver/dataplaneservice_controller.go | 205 +++++++ pkg/aggregator/apiserver/handler_apis.go | 68 +++ pkg/aggregator/apiserver/handler_plugin.go | 141 +++++ .../apiserver/handler_plugin_test.go | 202 +++++++ pkg/aggregator/apiserver/handler_proxy.go | 102 ++++ pkg/aggregator/apiserver/scheme/scheme.go | 32 ++ pkg/aggregator/examples/prometheus.yml | 9 + .../aggregation/v0alpha1/dataplaneservice.go | 204 +++++++ .../v0alpha1/dataplaneservicecondition.go | 66 +++ .../v0alpha1/dataplaneservicespec.go | 70 +++ .../v0alpha1/dataplaneservicestatus.go | 30 + .../aggregation/v0alpha1/service.go | 47 ++ .../applyconfiguration/internal/internal.go | 48 ++ .../generated/applyconfiguration/utils.go | 31 + .../clientset/versioned/clientset.go | 106 ++++ .../versioned/fake/clientset_generated.go | 71 +++ .../generated/clientset/versioned/fake/doc.go | 6 + .../clientset/versioned/fake/register.go | 42 ++ .../clientset/versioned/scheme/doc.go | 6 + .../clientset/versioned/scheme/register.go | 42 ++ .../v0alpha1/aggregation_client.go | 93 +++ .../aggregation/v0alpha1/dataplaneservice.go | 229 ++++++++ .../typed/aggregation/v0alpha1/doc.go | 6 + .../typed/aggregation/v0alpha1/fake/doc.go | 6 + .../v0alpha1/fake/fake_aggregation_client.go | 26 + .../v0alpha1/fake/fake_dataplaneservice.go | 164 ++++++ .../v0alpha1/generated_expansion.go | 7 + .../externalversions/aggregation/interface.go | 32 ++ .../aggregation/v0alpha1/dataplaneservice.go | 75 +++ .../aggregation/v0alpha1/interface.go | 31 + .../informers/externalversions/factory.go | 247 ++++++++ .../informers/externalversions/generic.go | 48 ++ .../internalinterfaces/factory_interfaces.go | 26 + .../aggregation/v0alpha1/dataplaneservice.go | 54 ++ .../v0alpha1/expansion_generated.go | 9 + pkg/aggregator/go.mod | 157 ++++++ pkg/aggregator/go.sum | 530 ++++++++++++++++++ .../registry/dataplaneservice/rest/storage.go | 33 ++ .../dataplaneservice/storage/storage.go | 151 +++++ .../registry/dataplaneservice/strategy.go | 170 ++++++ .../apiserver/aggregator/aggregator.go | 12 +- pkg/services/apiserver/config.go | 8 +- .../apiserver/options/grafana-aggregator.go | 94 ++++ .../{aggregator.go => kube-aggregator.go} | 14 +- pkg/services/apiserver/options/options.go | 29 +- pkg/services/apiserver/service.go | 156 +++++- 64 files changed, 5555 insertions(+), 57 deletions(-) create mode 100644 pkg/aggregator/apis/aggregation/doc.go create mode 100644 pkg/aggregator/apis/aggregation/install/install.go create mode 100644 pkg/aggregator/apis/aggregation/register.go create mode 100644 pkg/aggregator/apis/aggregation/types.go create mode 100644 pkg/aggregator/apis/aggregation/v0alpha1/doc.go create mode 100644 pkg/aggregator/apis/aggregation/v0alpha1/helper/helper.go create mode 100644 pkg/aggregator/apis/aggregation/v0alpha1/register.go create mode 100644 pkg/aggregator/apis/aggregation/v0alpha1/types.go create mode 100644 pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.conversion.go create mode 100644 pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.deepcopy.go create mode 100644 pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.defaults.go create mode 100644 pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.openapi.go create mode 100644 pkg/aggregator/apis/aggregation/zz_generated.deepcopy.go create mode 100644 pkg/aggregator/apiserver/apiserver.go create mode 100644 pkg/aggregator/apiserver/dataplaneservice_controller.go create mode 100644 pkg/aggregator/apiserver/handler_apis.go create mode 100644 pkg/aggregator/apiserver/handler_plugin.go create mode 100644 pkg/aggregator/apiserver/handler_plugin_test.go create mode 100644 pkg/aggregator/apiserver/handler_proxy.go create mode 100644 pkg/aggregator/apiserver/scheme/scheme.go create mode 100644 pkg/aggregator/examples/prometheus.yml create mode 100644 pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservice.go create mode 100644 pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicecondition.go create mode 100644 pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicespec.go create mode 100644 pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicestatus.go create mode 100644 pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/service.go create mode 100644 pkg/aggregator/generated/applyconfiguration/internal/internal.go create mode 100644 pkg/aggregator/generated/applyconfiguration/utils.go create mode 100644 pkg/aggregator/generated/clientset/versioned/clientset.go create mode 100644 pkg/aggregator/generated/clientset/versioned/fake/clientset_generated.go create mode 100644 pkg/aggregator/generated/clientset/versioned/fake/doc.go create mode 100644 pkg/aggregator/generated/clientset/versioned/fake/register.go create mode 100644 pkg/aggregator/generated/clientset/versioned/scheme/doc.go create mode 100644 pkg/aggregator/generated/clientset/versioned/scheme/register.go create mode 100644 pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/aggregation_client.go create mode 100644 pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/dataplaneservice.go create mode 100644 pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/doc.go create mode 100644 pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/doc.go create mode 100644 pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/fake_aggregation_client.go create mode 100644 pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/fake_dataplaneservice.go create mode 100644 pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/generated_expansion.go create mode 100644 pkg/aggregator/generated/informers/externalversions/aggregation/interface.go create mode 100644 pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1/dataplaneservice.go create mode 100644 pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1/interface.go create mode 100644 pkg/aggregator/generated/informers/externalversions/factory.go create mode 100644 pkg/aggregator/generated/informers/externalversions/generic.go create mode 100644 pkg/aggregator/generated/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 pkg/aggregator/generated/listers/aggregation/v0alpha1/dataplaneservice.go create mode 100644 pkg/aggregator/generated/listers/aggregation/v0alpha1/expansion_generated.go create mode 100644 pkg/aggregator/go.mod create mode 100644 pkg/aggregator/go.sum create mode 100644 pkg/aggregator/registry/dataplaneservice/rest/storage.go create mode 100644 pkg/aggregator/registry/dataplaneservice/storage/storage.go create mode 100644 pkg/aggregator/registry/dataplaneservice/strategy.go create mode 100644 pkg/services/apiserver/options/grafana-aggregator.go rename pkg/services/apiserver/options/{aggregator.go => kube-aggregator.go} (90%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2f250370c42..ee39a1c4d1f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -106,6 +106,7 @@ /pkg/semconv/ @grafana/grafana-backend-group /pkg/server/ @grafana/grafana-backend-group /pkg/apiserver @grafana/grafana-app-platform-squad +/pkg/aggregator @grafana/grafana-app-platform-squad /pkg/apimachinery @grafana/grafana-app-platform-squad /pkg/apimachinery/identity/ @grafana/identity-squad /pkg/apimachinery/errutil/ @grafana/grafana-backend-group diff --git a/.golangci.toml b/.golangci.toml index b96e063439c..f45ec1af4b7 100644 --- a/.golangci.toml +++ b/.golangci.toml @@ -98,6 +98,21 @@ files = [ "**/pkg/apimachinery/**/*" ] +[linters-settings.depguard.rules.aggregator] +list-mode = "lax" +allow = [ + "github.com/grafana/grafana/pkg/aggregator", + "github.com/grafana/grafana/pkg/semconv", + "github.com/grafana/grafana/pkg/apimachinery", +] +deny = [ + { pkg = "github.com/grafana/grafana/pkg", desc = "apimachinery is not allowed to import grafana core" } +] +files = [ + "./pkg/aggregator/*", + "./pkg/aggregator/**/*" +] + [linters-settings.depguard.rules.promlib] list-mode = "lax" # allow unless explicitely denied deny = [ @@ -107,7 +122,6 @@ allow = [ "github.com/grafana/grafana/pkg/promlib" ] files = [ - "**/pkg/promlib/*", "**/pkg/promlib/**/*" ] diff --git a/go.work b/go.work index aefa6dda97f..5e9b02fc37a 100644 --- a/go.work +++ b/go.work @@ -5,6 +5,7 @@ go 1.22.4 use ( . // skip:golangci-lint + ./pkg/aggregator ./pkg/apimachinery ./pkg/apiserver ./pkg/build diff --git a/go.work.sum b/go.work.sum index 61eb6784916..b9d097c6d25 100644 --- a/go.work.sum +++ b/go.work.sum @@ -268,6 +268,8 @@ github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nC github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= +github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= +github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= @@ -386,8 +388,6 @@ github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 h1:EcQR3gusLHN github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= -github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= -github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/go-jsonnet v0.18.0 h1:/6pTy6g+Jh1a1I2UMoAODkqELFiVIdOxbNwv0DDzoOg= github.com/google/go-jsonnet v0.18.0/go.mod h1:C3fTzyVJDslXdiTqw/bTFk7vSGyCtH3MGRbDfvEwGd0= github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9 h1:OF1IPgv+F4NmqmJ98KTjdN97Vs1JxDPB3vbmYzV2dpk= @@ -407,7 +407,6 @@ github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/grafana/authlib/claims v0.0.0-20240809095826-8eb5495c0b2a/go.mod h1:r+F8H6awwjNQt/KPZ2GNwjk8TvsJ7/gxzkXN26GlL/A= github.com/grafana/gomemcache v0.0.0-20240229205252-cd6a66d6fb56/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU= github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= @@ -730,6 +729,8 @@ github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs= go.einride.tech/aip v0.66.0 h1:XfV+NQX6L7EOYK11yoHHFtndeaWh3KbD9/cN/6iWEt8= +go.etcd.io/gofail v0.1.0 h1:XItAMIhOojXFQMgrxjnd2EIIHun/d5qL0Pf7FzVTkFg= +go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= go.opentelemetry.io/collector v0.97.0 h1:qyOju13byHIKEK/JehmTiGMj4pFLa4kDyrOCtTmjHU0= go.opentelemetry.io/collector v0.97.0/go.mod h1:V6xquYAaO2VHVu4DBK28JYuikRdZajh7DH5Vl/Y8NiA= go.opentelemetry.io/collector/component v0.97.0 h1:vanKhXl5nptN8igRH4PqVYHOILif653vaPIKv6LCZCI= @@ -876,8 +877,6 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= honnef.co/go/tools v0.1.3 h1:qTakTkI6ni6LFD5sBwwsdSO+AQqbSIxOauHTTQKZ/7o= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -k8s.io/apimachinery v0.31.0-rc.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.0-rc.1/go.mod h1:CdFvqtAIiWDfZl1LMixuXYGpttymfuopCol/F6AbxmI= k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/shsbSYiWXmNGlks= k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1X/TByhmAoILTarmzo= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= diff --git a/pkg/aggregator/apis/aggregation/doc.go b/pkg/aggregator/apis/aggregation/doc.go new file mode 100644 index 00000000000..34d55388512 --- /dev/null +++ b/pkg/aggregator/apis/aggregation/doc.go @@ -0,0 +1,4 @@ +// +k8s:deepcopy-gen=package +// +groupName=aggregation.grafana.app + +package aggregation // import "github.com/grafana/grafana/pkg/aggregator/apis/aggregation" diff --git a/pkg/aggregator/apis/aggregation/install/install.go b/pkg/aggregator/apis/aggregation/install/install.go new file mode 100644 index 00000000000..dbf11fa434c --- /dev/null +++ b/pkg/aggregator/apis/aggregation/install/install.go @@ -0,0 +1,16 @@ +package install + +import ( + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + + aggregation "github.com/grafana/grafana/pkg/aggregator/apis/aggregation" + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" +) + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + utilruntime.Must(aggregation.AddToScheme(scheme)) + utilruntime.Must(v0alpha1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(v0alpha1.SchemeGroupVersion)) +} diff --git a/pkg/aggregator/apis/aggregation/register.go b/pkg/aggregator/apis/aggregation/register.go new file mode 100644 index 00000000000..4a5c900c5b6 --- /dev/null +++ b/pkg/aggregator/apis/aggregation/register.go @@ -0,0 +1,40 @@ +package aggregation + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +const ( + GROUP = "aggregation.grafana.app" + VERSION = runtime.APIVersionInternal + APIVERSION = GROUP + "/" + VERSION +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: GROUP, Version: VERSION} + + // SchemaBuilder is used by standard codegen + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + localSchemeBuilder.Register(addKnownTypes) +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &DataPlaneService{}, + &DataPlaneServiceList{}, + ) + return nil +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/pkg/aggregator/apis/aggregation/types.go b/pkg/aggregator/apis/aggregation/types.go new file mode 100644 index 00000000000..cb7509cbd9d --- /dev/null +++ b/pkg/aggregator/apis/aggregation/types.go @@ -0,0 +1,136 @@ +package aggregation + +import ( + "github.com/grafana/grafana-plugin-sdk-go/backend" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type DataPlaneService struct { + metav1.TypeMeta + metav1.ObjectMeta + + Spec DataPlaneServiceSpec + Status DataPlaneServiceStatus +} + +type DataPlaneServiceSpec struct { + PluginID string + PluginType PluginType + Group string + Version string + // Services is a list of services that the proxied service provides. + // +optional + // +listType=map + // +listMapKey=type + Services []Service +} + +// Service defines the type of service the proxied service provides. +type Service struct { + // Type is the type of service to proxy. + Type ServiceType + // Method is the HTTP method to use when proxying the service. + // +optional + Method string + // Path is used by the CustomRouteServiceType and SubResourceServiceType to specify the path to the endpoint. + // +optional + Path string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type DataPlaneServiceList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []DataPlaneService +} + +// PluginType defines the type of plugin backing the proxied service. +// +enum +type PluginType string + +// PluginType values +const ( + AppPluginType PluginType = "app" + DataSourcePluginType PluginType = "datasource" +) + +// ServiceType defines the type of services the proxied service provides. +// +enum +type ServiceType string + +// ServiceType values +const ( + // AdmissionControlServiceType maps to pluginv2.AdmissionControl + AdmissionControlServiceType ServiceType = "admission" + // ConversionServiceType maps to pluginv2.ResourceConversion + ConversionServiceType ServiceType = "conversion" + // DataSourceServiceType maps to pluginv2.Data + DataServiceType ServiceType = "data" + // StreamServiceType maps to pluginv2.Stream + StreamServiceType ServiceType = "stream" + // RouteServiceType maps pluginv2.Resource + RouteServiceType ServiceType = "route" + // DataSourceProxyServiceType is a reverse proxy for making requests directly to the HTTP URL specified in datasource instance settings. + DataSourceProxyServiceType ServiceType = "datsource-proxy" +) + +// ConditionStatus indicates the status of a condition (true, false, or unknown). +type ConditionStatus string + +// These are valid condition statuses. "ConditionTrue" means a resource is in the condition; +// "ConditionFalse" means a resource is not in the condition; "ConditionUnknown" means kubernetes +// can't decide if a resource is in the condition or not. In the future, we could add other +// intermediate conditions, e.g. ConditionDegraded. +const ( + ConditionTrue ConditionStatus = "True" + ConditionFalse ConditionStatus = "False" + ConditionUnknown ConditionStatus = "Unknown" +) + +// DataPlaneServiceConditionType is a valid value for DataPlaneServiceCondition.Type +type DataPlaneServiceConditionType string + +const ( + // Available indicates that the service exists and is reachable + Available DataPlaneServiceConditionType = "Available" +) + +// DataPlaneServiceCondition describes the state of an DataPlaneService at a particular point +type DataPlaneServiceCondition struct { + // Type is the type of the condition. + Type DataPlaneServiceConditionType + // Status is the status of the condition. + // Can be True, False, Unknown. + Status ConditionStatus + // Last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time + // Unique, one-word, CamelCase reason for the condition's last transition. + // +optional + Reason string + // Human-readable message indicating details about last transition. + // +optional + Message string +} + +// DataPlaneServiceStatus contains derived information about a remote DataPlaneService. +type DataPlaneServiceStatus struct { + // Current service state of DataPlaneService. + // +optional + // +listType=map + // +listMapKey=type + Conditions []DataPlaneServiceCondition +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type QueryDataResponse struct { + metav1.TypeMeta + + // Backend wrapper (external dependency) + backend.QueryDataResponse +} diff --git a/pkg/aggregator/apis/aggregation/v0alpha1/doc.go b/pkg/aggregator/apis/aggregation/v0alpha1/doc.go new file mode 100644 index 00000000000..c43e600acfe --- /dev/null +++ b/pkg/aggregator/apis/aggregation/v0alpha1/doc.go @@ -0,0 +1,7 @@ +// +k8s:deepcopy-gen=package +// +k8s:openapi-gen=true +// +k8s:defaulter-gen=TypeMeta +// +k8s:conversion-gen=github.com/grafana/grafana/pkg/aggregator/apis/aggregation +// +groupName=aggregation.grafana.app + +package v0alpha1 // import "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" diff --git a/pkg/aggregator/apis/aggregation/v0alpha1/helper/helper.go b/pkg/aggregator/apis/aggregation/v0alpha1/helper/helper.go new file mode 100644 index 00000000000..0ca0a51fff0 --- /dev/null +++ b/pkg/aggregator/apis/aggregation/v0alpha1/helper/helper.go @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Provenance-includes-location: https://github.com/kubernetes/kube-aggregator/blob/master/pkg/apis/apiregistration/v1/helper/helpers.go +// Provenance-includes-license: Apache-2.0 +// Provenance-includes-copyright: The Kubernetes Authors. + +package helper + +import ( + "strings" + + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// DataPlaneServiceNameToGroupVersion returns the GroupVersion for a given dataplaneServiceNam. The name +// must be valid, but any object you get back from an informer will be valid. +func DataPlaneServiceNameToGroupVersion(dataplaneServiceName string) schema.GroupVersion { + tokens := strings.SplitN(dataplaneServiceName, ".", 2) + return schema.GroupVersion{Group: tokens[1], Version: tokens[0]} +} + +// SetDataPlaneServiceCondition sets the status condition. It either overwrites the existing one or +// creates a new one +func SetDataPlaneServiceCondition(dataplaneService *v0alpha1.DataPlaneService, newCondition v0alpha1.DataPlaneServiceCondition) { + existingCondition := GetDataPlaneServiceConditionByType(dataplaneService, newCondition.Type) + if existingCondition == nil { + dataplaneService.Status.Conditions = append(dataplaneService.Status.Conditions, newCondition) + return + } + + if existingCondition.Status != newCondition.Status { + existingCondition.Status = newCondition.Status + existingCondition.LastTransitionTime = newCondition.LastTransitionTime + } + + existingCondition.Reason = newCondition.Reason + existingCondition.Message = newCondition.Message +} + +// IsDataPlaneServiceConditionTrue indicates if the condition is present and strictly true +func IsDataPlaneServiceConditionTrue(dataplaneService *v0alpha1.DataPlaneService, conditionType v0alpha1.DataPlaneServiceConditionType) bool { + condition := GetDataPlaneServiceConditionByType(dataplaneService, conditionType) + return condition != nil && condition.Status == v0alpha1.ConditionTrue +} + +// GetDataPlaneServiceConditionByType gets an *DataPlaneServiceCondition by DataPlaneServiceConditionType if present +func GetDataPlaneServiceConditionByType(dataplaneService *v0alpha1.DataPlaneService, conditionType v0alpha1.DataPlaneServiceConditionType) *v0alpha1.DataPlaneServiceCondition { + for i := range dataplaneService.Status.Conditions { + if dataplaneService.Status.Conditions[i].Type == conditionType { + return &dataplaneService.Status.Conditions[i] + } + } + return nil +} diff --git a/pkg/aggregator/apis/aggregation/v0alpha1/register.go b/pkg/aggregator/apis/aggregation/v0alpha1/register.go new file mode 100644 index 00000000000..7d1ac05cc2b --- /dev/null +++ b/pkg/aggregator/apis/aggregation/v0alpha1/register.go @@ -0,0 +1,52 @@ +package v0alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + "github.com/grafana/grafana/pkg/apimachinery/utils" +) + +const ( + GROUP = "aggregation.grafana.app" + VERSION = "v0alpha1" + APIVERSION = GROUP + "/" + VERSION +) + +var DataPlaneServiceResourceInfo = common.NewResourceInfo(GROUP, VERSION, + "dataplaneservices", "dataplaneservice", "DataPlaneService", + func() runtime.Object { return &DataPlaneService{} }, + func() runtime.Object { return &DataPlaneServiceList{} }, + utils.TableColumns{}, // default table converter +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: GROUP, Version: VERSION} + + // SchemaBuilder is used by standard codegen + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + localSchemeBuilder.Register(addKnownTypes, RegisterDefaults) +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &DataPlaneService{}, + &DataPlaneServiceList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/pkg/aggregator/apis/aggregation/v0alpha1/types.go b/pkg/aggregator/apis/aggregation/v0alpha1/types.go new file mode 100644 index 00000000000..0f48260728d --- /dev/null +++ b/pkg/aggregator/apis/aggregation/v0alpha1/types.go @@ -0,0 +1,136 @@ +package v0alpha1 + +import ( + "github.com/grafana/grafana-plugin-sdk-go/backend" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type DataPlaneService struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec DataPlaneServiceSpec `json:"spec,omitempty"` + Status DataPlaneServiceStatus `json:"status,omitempty"` +} + +type DataPlaneServiceSpec struct { + PluginID string `json:"pluginID"` + PluginType PluginType `json:"pluginType"` + Group string `json:"group"` + Version string `json:"version"` + // Services is a list of services that the proxied service provides. + // +optional + // +listType=map + // +listMapKey=type + Services []Service `json:"services"` +} + +// Service defines the type of service the proxied service provides. +type Service struct { + // Type is the type of service to proxy. + Type ServiceType `json:"type"` + // Method is the HTTP method to use when proxying the service. + // +optional + Method string `json:"method,omitempty"` + // Path is used by the CustomRouteServiceType and SubResourceServiceType to specify the path to the endpoint. + // +optional + Path string `json:"path,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type DataPlaneServiceList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []DataPlaneService `json:"items,omitempty"` +} + +// PluginType defines the type of plugin backing the proxied service. +// +enum +type PluginType string + +// PluginType values +const ( + AppPluginType PluginType = "app" + DataSourcePluginType PluginType = "datasource" +) + +// ServiceType defines the type of services the proxied service provides. +// +enum +type ServiceType string + +// ServiceType values +const ( + // AdmissionControlServiceType maps to pluginv2.AdmissionControl + AdmissionControlServiceType ServiceType = "admission" + // ConversionServiceType maps to pluginv2.ResourceConversion + ConversionServiceType ServiceType = "conversion" + // DataSourceServiceType maps to pluginv2.Data + DataServiceType ServiceType = "data" + // StreamServiceType maps to pluginv2.Stream + StreamServiceType ServiceType = "stream" + // RouteServiceType maps pluginv2.Resource + RouteServiceType ServiceType = "route" + // DataSourceProxyServiceType is a reverse proxy for making requests directly to the HTTP URL specified in datasource instance settings. + DataSourceProxyServiceType ServiceType = "datsource-proxy" +) + +// ConditionStatus indicates the status of a condition (true, false, or unknown). +type ConditionStatus string + +// These are valid condition statuses. "ConditionTrue" means a resource is in the condition; +// "ConditionFalse" means a resource is not in the condition; "ConditionUnknown" means kubernetes +// can't decide if a resource is in the condition or not. In the future, we could add other +// intermediate conditions, e.g. ConditionDegraded. +const ( + ConditionTrue ConditionStatus = "True" + ConditionFalse ConditionStatus = "False" + ConditionUnknown ConditionStatus = "Unknown" +) + +// DataPlaneServiceConditionType is a valid value for DataPlaneServiceCondition.Type +type DataPlaneServiceConditionType string + +const ( + // Available indicates that the service exists and is reachable + Available DataPlaneServiceConditionType = "Available" +) + +// DataPlaneServiceCondition describes the state of an DataPlaneService at a particular point +type DataPlaneServiceCondition struct { + // Type is the type of the condition. + Type DataPlaneServiceConditionType `json:"type"` + // Status is the status of the condition. + // Can be True, False, Unknown. + Status ConditionStatus `json:"status"` + // Last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + // Unique, one-word, CamelCase reason for the condition's last transition. + // +optional + Reason string `json:"reason,omitempty"` + // Human-readable message indicating details about last transition. + // +optional + Message string `json:"message,omitempty"` +} + +// DataPlaneServiceStatus contains derived information about a remote DataPlaneService. +type DataPlaneServiceStatus struct { + // Current service state of DataPlaneService. + // +optional + // +listType=map + // +listMapKey=type + Conditions []DataPlaneServiceCondition `json:"conditions,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type QueryDataResponse struct { + metav1.TypeMeta `json:",inline"` + + // Backend wrapper (external dependency) + backend.QueryDataResponse `json:",inline"` +} diff --git a/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.conversion.go b/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.conversion.go new file mode 100644 index 00000000000..e36c9b6037c --- /dev/null +++ b/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.conversion.go @@ -0,0 +1,270 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by conversion-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + unsafe "unsafe" + + aggregation "github.com/grafana/grafana/pkg/aggregator/apis/aggregation" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*DataPlaneService)(nil), (*aggregation.DataPlaneService)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_DataPlaneService_To_aggregation_DataPlaneService(a.(*DataPlaneService), b.(*aggregation.DataPlaneService), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*aggregation.DataPlaneService)(nil), (*DataPlaneService)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_aggregation_DataPlaneService_To_v0alpha1_DataPlaneService(a.(*aggregation.DataPlaneService), b.(*DataPlaneService), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*DataPlaneServiceCondition)(nil), (*aggregation.DataPlaneServiceCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_DataPlaneServiceCondition_To_aggregation_DataPlaneServiceCondition(a.(*DataPlaneServiceCondition), b.(*aggregation.DataPlaneServiceCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*aggregation.DataPlaneServiceCondition)(nil), (*DataPlaneServiceCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_aggregation_DataPlaneServiceCondition_To_v0alpha1_DataPlaneServiceCondition(a.(*aggregation.DataPlaneServiceCondition), b.(*DataPlaneServiceCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*DataPlaneServiceList)(nil), (*aggregation.DataPlaneServiceList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_DataPlaneServiceList_To_aggregation_DataPlaneServiceList(a.(*DataPlaneServiceList), b.(*aggregation.DataPlaneServiceList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*aggregation.DataPlaneServiceList)(nil), (*DataPlaneServiceList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_aggregation_DataPlaneServiceList_To_v0alpha1_DataPlaneServiceList(a.(*aggregation.DataPlaneServiceList), b.(*DataPlaneServiceList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*DataPlaneServiceSpec)(nil), (*aggregation.DataPlaneServiceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_DataPlaneServiceSpec_To_aggregation_DataPlaneServiceSpec(a.(*DataPlaneServiceSpec), b.(*aggregation.DataPlaneServiceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*aggregation.DataPlaneServiceSpec)(nil), (*DataPlaneServiceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_aggregation_DataPlaneServiceSpec_To_v0alpha1_DataPlaneServiceSpec(a.(*aggregation.DataPlaneServiceSpec), b.(*DataPlaneServiceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*DataPlaneServiceStatus)(nil), (*aggregation.DataPlaneServiceStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_DataPlaneServiceStatus_To_aggregation_DataPlaneServiceStatus(a.(*DataPlaneServiceStatus), b.(*aggregation.DataPlaneServiceStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*aggregation.DataPlaneServiceStatus)(nil), (*DataPlaneServiceStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_aggregation_DataPlaneServiceStatus_To_v0alpha1_DataPlaneServiceStatus(a.(*aggregation.DataPlaneServiceStatus), b.(*DataPlaneServiceStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*QueryDataResponse)(nil), (*aggregation.QueryDataResponse)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_QueryDataResponse_To_aggregation_QueryDataResponse(a.(*QueryDataResponse), b.(*aggregation.QueryDataResponse), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*aggregation.QueryDataResponse)(nil), (*QueryDataResponse)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_aggregation_QueryDataResponse_To_v0alpha1_QueryDataResponse(a.(*aggregation.QueryDataResponse), b.(*QueryDataResponse), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Service)(nil), (*aggregation.Service)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_Service_To_aggregation_Service(a.(*Service), b.(*aggregation.Service), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*aggregation.Service)(nil), (*Service)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_aggregation_Service_To_v0alpha1_Service(a.(*aggregation.Service), b.(*Service), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v0alpha1_DataPlaneService_To_aggregation_DataPlaneService(in *DataPlaneService, out *aggregation.DataPlaneService, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v0alpha1_DataPlaneServiceSpec_To_aggregation_DataPlaneServiceSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v0alpha1_DataPlaneServiceStatus_To_aggregation_DataPlaneServiceStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v0alpha1_DataPlaneService_To_aggregation_DataPlaneService is an autogenerated conversion function. +func Convert_v0alpha1_DataPlaneService_To_aggregation_DataPlaneService(in *DataPlaneService, out *aggregation.DataPlaneService, s conversion.Scope) error { + return autoConvert_v0alpha1_DataPlaneService_To_aggregation_DataPlaneService(in, out, s) +} + +func autoConvert_aggregation_DataPlaneService_To_v0alpha1_DataPlaneService(in *aggregation.DataPlaneService, out *DataPlaneService, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_aggregation_DataPlaneServiceSpec_To_v0alpha1_DataPlaneServiceSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_aggregation_DataPlaneServiceStatus_To_v0alpha1_DataPlaneServiceStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_aggregation_DataPlaneService_To_v0alpha1_DataPlaneService is an autogenerated conversion function. +func Convert_aggregation_DataPlaneService_To_v0alpha1_DataPlaneService(in *aggregation.DataPlaneService, out *DataPlaneService, s conversion.Scope) error { + return autoConvert_aggregation_DataPlaneService_To_v0alpha1_DataPlaneService(in, out, s) +} + +func autoConvert_v0alpha1_DataPlaneServiceCondition_To_aggregation_DataPlaneServiceCondition(in *DataPlaneServiceCondition, out *aggregation.DataPlaneServiceCondition, s conversion.Scope) error { + out.Type = aggregation.DataPlaneServiceConditionType(in.Type) + out.Status = aggregation.ConditionStatus(in.Status) + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_v0alpha1_DataPlaneServiceCondition_To_aggregation_DataPlaneServiceCondition is an autogenerated conversion function. +func Convert_v0alpha1_DataPlaneServiceCondition_To_aggregation_DataPlaneServiceCondition(in *DataPlaneServiceCondition, out *aggregation.DataPlaneServiceCondition, s conversion.Scope) error { + return autoConvert_v0alpha1_DataPlaneServiceCondition_To_aggregation_DataPlaneServiceCondition(in, out, s) +} + +func autoConvert_aggregation_DataPlaneServiceCondition_To_v0alpha1_DataPlaneServiceCondition(in *aggregation.DataPlaneServiceCondition, out *DataPlaneServiceCondition, s conversion.Scope) error { + out.Type = DataPlaneServiceConditionType(in.Type) + out.Status = ConditionStatus(in.Status) + out.LastTransitionTime = in.LastTransitionTime + out.Reason = in.Reason + out.Message = in.Message + return nil +} + +// Convert_aggregation_DataPlaneServiceCondition_To_v0alpha1_DataPlaneServiceCondition is an autogenerated conversion function. +func Convert_aggregation_DataPlaneServiceCondition_To_v0alpha1_DataPlaneServiceCondition(in *aggregation.DataPlaneServiceCondition, out *DataPlaneServiceCondition, s conversion.Scope) error { + return autoConvert_aggregation_DataPlaneServiceCondition_To_v0alpha1_DataPlaneServiceCondition(in, out, s) +} + +func autoConvert_v0alpha1_DataPlaneServiceList_To_aggregation_DataPlaneServiceList(in *DataPlaneServiceList, out *aggregation.DataPlaneServiceList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]aggregation.DataPlaneService)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v0alpha1_DataPlaneServiceList_To_aggregation_DataPlaneServiceList is an autogenerated conversion function. +func Convert_v0alpha1_DataPlaneServiceList_To_aggregation_DataPlaneServiceList(in *DataPlaneServiceList, out *aggregation.DataPlaneServiceList, s conversion.Scope) error { + return autoConvert_v0alpha1_DataPlaneServiceList_To_aggregation_DataPlaneServiceList(in, out, s) +} + +func autoConvert_aggregation_DataPlaneServiceList_To_v0alpha1_DataPlaneServiceList(in *aggregation.DataPlaneServiceList, out *DataPlaneServiceList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]DataPlaneService)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_aggregation_DataPlaneServiceList_To_v0alpha1_DataPlaneServiceList is an autogenerated conversion function. +func Convert_aggregation_DataPlaneServiceList_To_v0alpha1_DataPlaneServiceList(in *aggregation.DataPlaneServiceList, out *DataPlaneServiceList, s conversion.Scope) error { + return autoConvert_aggregation_DataPlaneServiceList_To_v0alpha1_DataPlaneServiceList(in, out, s) +} + +func autoConvert_v0alpha1_DataPlaneServiceSpec_To_aggregation_DataPlaneServiceSpec(in *DataPlaneServiceSpec, out *aggregation.DataPlaneServiceSpec, s conversion.Scope) error { + out.PluginID = in.PluginID + out.PluginType = aggregation.PluginType(in.PluginType) + out.Group = in.Group + out.Version = in.Version + out.Services = *(*[]aggregation.Service)(unsafe.Pointer(&in.Services)) + return nil +} + +// Convert_v0alpha1_DataPlaneServiceSpec_To_aggregation_DataPlaneServiceSpec is an autogenerated conversion function. +func Convert_v0alpha1_DataPlaneServiceSpec_To_aggregation_DataPlaneServiceSpec(in *DataPlaneServiceSpec, out *aggregation.DataPlaneServiceSpec, s conversion.Scope) error { + return autoConvert_v0alpha1_DataPlaneServiceSpec_To_aggregation_DataPlaneServiceSpec(in, out, s) +} + +func autoConvert_aggregation_DataPlaneServiceSpec_To_v0alpha1_DataPlaneServiceSpec(in *aggregation.DataPlaneServiceSpec, out *DataPlaneServiceSpec, s conversion.Scope) error { + out.PluginID = in.PluginID + out.PluginType = PluginType(in.PluginType) + out.Group = in.Group + out.Version = in.Version + out.Services = *(*[]Service)(unsafe.Pointer(&in.Services)) + return nil +} + +// Convert_aggregation_DataPlaneServiceSpec_To_v0alpha1_DataPlaneServiceSpec is an autogenerated conversion function. +func Convert_aggregation_DataPlaneServiceSpec_To_v0alpha1_DataPlaneServiceSpec(in *aggregation.DataPlaneServiceSpec, out *DataPlaneServiceSpec, s conversion.Scope) error { + return autoConvert_aggregation_DataPlaneServiceSpec_To_v0alpha1_DataPlaneServiceSpec(in, out, s) +} + +func autoConvert_v0alpha1_DataPlaneServiceStatus_To_aggregation_DataPlaneServiceStatus(in *DataPlaneServiceStatus, out *aggregation.DataPlaneServiceStatus, s conversion.Scope) error { + out.Conditions = *(*[]aggregation.DataPlaneServiceCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_v0alpha1_DataPlaneServiceStatus_To_aggregation_DataPlaneServiceStatus is an autogenerated conversion function. +func Convert_v0alpha1_DataPlaneServiceStatus_To_aggregation_DataPlaneServiceStatus(in *DataPlaneServiceStatus, out *aggregation.DataPlaneServiceStatus, s conversion.Scope) error { + return autoConvert_v0alpha1_DataPlaneServiceStatus_To_aggregation_DataPlaneServiceStatus(in, out, s) +} + +func autoConvert_aggregation_DataPlaneServiceStatus_To_v0alpha1_DataPlaneServiceStatus(in *aggregation.DataPlaneServiceStatus, out *DataPlaneServiceStatus, s conversion.Scope) error { + out.Conditions = *(*[]DataPlaneServiceCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_aggregation_DataPlaneServiceStatus_To_v0alpha1_DataPlaneServiceStatus is an autogenerated conversion function. +func Convert_aggregation_DataPlaneServiceStatus_To_v0alpha1_DataPlaneServiceStatus(in *aggregation.DataPlaneServiceStatus, out *DataPlaneServiceStatus, s conversion.Scope) error { + return autoConvert_aggregation_DataPlaneServiceStatus_To_v0alpha1_DataPlaneServiceStatus(in, out, s) +} + +func autoConvert_v0alpha1_QueryDataResponse_To_aggregation_QueryDataResponse(in *QueryDataResponse, out *aggregation.QueryDataResponse, s conversion.Scope) error { + out.QueryDataResponse = in.QueryDataResponse + return nil +} + +// Convert_v0alpha1_QueryDataResponse_To_aggregation_QueryDataResponse is an autogenerated conversion function. +func Convert_v0alpha1_QueryDataResponse_To_aggregation_QueryDataResponse(in *QueryDataResponse, out *aggregation.QueryDataResponse, s conversion.Scope) error { + return autoConvert_v0alpha1_QueryDataResponse_To_aggregation_QueryDataResponse(in, out, s) +} + +func autoConvert_aggregation_QueryDataResponse_To_v0alpha1_QueryDataResponse(in *aggregation.QueryDataResponse, out *QueryDataResponse, s conversion.Scope) error { + out.QueryDataResponse = in.QueryDataResponse + return nil +} + +// Convert_aggregation_QueryDataResponse_To_v0alpha1_QueryDataResponse is an autogenerated conversion function. +func Convert_aggregation_QueryDataResponse_To_v0alpha1_QueryDataResponse(in *aggregation.QueryDataResponse, out *QueryDataResponse, s conversion.Scope) error { + return autoConvert_aggregation_QueryDataResponse_To_v0alpha1_QueryDataResponse(in, out, s) +} + +func autoConvert_v0alpha1_Service_To_aggregation_Service(in *Service, out *aggregation.Service, s conversion.Scope) error { + out.Type = aggregation.ServiceType(in.Type) + out.Method = in.Method + out.Path = in.Path + return nil +} + +// Convert_v0alpha1_Service_To_aggregation_Service is an autogenerated conversion function. +func Convert_v0alpha1_Service_To_aggregation_Service(in *Service, out *aggregation.Service, s conversion.Scope) error { + return autoConvert_v0alpha1_Service_To_aggregation_Service(in, out, s) +} + +func autoConvert_aggregation_Service_To_v0alpha1_Service(in *aggregation.Service, out *Service, s conversion.Scope) error { + out.Type = ServiceType(in.Type) + out.Method = in.Method + out.Path = in.Path + return nil +} + +// Convert_aggregation_Service_To_v0alpha1_Service is an autogenerated conversion function. +func Convert_aggregation_Service_To_v0alpha1_Service(in *aggregation.Service, out *Service, s conversion.Scope) error { + return autoConvert_aggregation_Service_To_v0alpha1_Service(in, out, s) +} diff --git a/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.deepcopy.go b/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..a6da8482db2 --- /dev/null +++ b/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.deepcopy.go @@ -0,0 +1,176 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneService) DeepCopyInto(out *DataPlaneService) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneService. +func (in *DataPlaneService) DeepCopy() *DataPlaneService { + if in == nil { + return nil + } + out := new(DataPlaneService) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DataPlaneService) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneServiceCondition) DeepCopyInto(out *DataPlaneServiceCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneServiceCondition. +func (in *DataPlaneServiceCondition) DeepCopy() *DataPlaneServiceCondition { + if in == nil { + return nil + } + out := new(DataPlaneServiceCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneServiceList) DeepCopyInto(out *DataPlaneServiceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DataPlaneService, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneServiceList. +func (in *DataPlaneServiceList) DeepCopy() *DataPlaneServiceList { + if in == nil { + return nil + } + out := new(DataPlaneServiceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DataPlaneServiceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneServiceSpec) DeepCopyInto(out *DataPlaneServiceSpec) { + *out = *in + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]Service, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneServiceSpec. +func (in *DataPlaneServiceSpec) DeepCopy() *DataPlaneServiceSpec { + if in == nil { + return nil + } + out := new(DataPlaneServiceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneServiceStatus) DeepCopyInto(out *DataPlaneServiceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]DataPlaneServiceCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneServiceStatus. +func (in *DataPlaneServiceStatus) DeepCopy() *DataPlaneServiceStatus { + if in == nil { + return nil + } + out := new(DataPlaneServiceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *QueryDataResponse) DeepCopyInto(out *QueryDataResponse) { + *out = *in + out.TypeMeta = in.TypeMeta + in.QueryDataResponse.DeepCopyInto(&out.QueryDataResponse) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new QueryDataResponse. +func (in *QueryDataResponse) DeepCopy() *QueryDataResponse { + if in == nil { + return nil + } + out := new(QueryDataResponse) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *QueryDataResponse) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Service) DeepCopyInto(out *Service) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service. +func (in *Service) DeepCopy() *Service { + if in == nil { + return nil + } + out := new(Service) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.defaults.go b/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.defaults.go new file mode 100644 index 00000000000..238fc2f4edc --- /dev/null +++ b/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.defaults.go @@ -0,0 +1,19 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.openapi.go b/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.openapi.go new file mode 100644 index 00000000000..cd864d8edd5 --- /dev/null +++ b/pkg/aggregator/apis/aggregation/v0alpha1/zz_generated.openapi.go @@ -0,0 +1,357 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by openapi-gen. DO NOT EDIT. + +// This file was autogenerated by openapi-gen. Do not edit it manually! + +package v0alpha1 + +import ( + common "k8s.io/kube-openapi/pkg/common" + spec "k8s.io/kube-openapi/pkg/validation/spec" +) + +func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { + return map[string]common.OpenAPIDefinition{ + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneService": schema_aggregator_apis_aggregation_v0alpha1_DataPlaneService(ref), + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceCondition": schema_aggregator_apis_aggregation_v0alpha1_DataPlaneServiceCondition(ref), + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceList": schema_aggregator_apis_aggregation_v0alpha1_DataPlaneServiceList(ref), + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceSpec": schema_aggregator_apis_aggregation_v0alpha1_DataPlaneServiceSpec(ref), + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceStatus": schema_aggregator_apis_aggregation_v0alpha1_DataPlaneServiceStatus(ref), + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.QueryDataResponse": schema_aggregator_apis_aggregation_v0alpha1_QueryDataResponse(ref), + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.Service": schema_aggregator_apis_aggregation_v0alpha1_Service(ref), + } +} + +func schema_aggregator_apis_aggregation_v0alpha1_DataPlaneService(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceSpec", "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_aggregator_apis_aggregation_v0alpha1_DataPlaneServiceCondition(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DataPlaneServiceCondition describes the state of an DataPlaneService at a particular point", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Type is the type of the condition.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "Status is the status of the condition. Can be True, False, Unknown.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "lastTransitionTime": { + SchemaProps: spec.SchemaProps{ + Description: "Last time the condition transitioned from one status to another.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "reason": { + SchemaProps: spec.SchemaProps{ + Description: "Unique, one-word, CamelCase reason for the condition's last transition.", + Type: []string{"string"}, + Format: "", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "Human-readable message indicating details about last transition.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"type", "status"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_aggregator_apis_aggregation_v0alpha1_DataPlaneServiceList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneService"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneService", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_aggregator_apis_aggregation_v0alpha1_DataPlaneServiceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "pluginID": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "pluginType": { + SchemaProps: spec.SchemaProps{ + Description: "Possible enum values:\n - `\"app\"`\n - `\"datasource\"`", + Default: "", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"app", "datasource"}, + }, + }, + "group": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "services": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Services is a list of services that the proxied service provides.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.Service"), + }, + }, + }, + }, + }, + }, + Required: []string{"pluginID", "pluginType", "group", "version"}, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.Service"}, + } +} + +func schema_aggregator_apis_aggregation_v0alpha1_DataPlaneServiceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DataPlaneServiceStatus contains derived information about a remote DataPlaneService.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Current service state of DataPlaneService.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceCondition"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1.DataPlaneServiceCondition"}, + } +} + +func schema_aggregator_apis_aggregation_v0alpha1_QueryDataResponse(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "results": { + SchemaProps: spec.SchemaProps{ + Description: "Responses is a map of RefIDs (Unique Query ID) to *DataResponse.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana-plugin-sdk-go/backend.DataResponse"), + }, + }, + }, + }, + }, + }, + Required: []string{"results"}, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana-plugin-sdk-go/backend.DataResponse"}, + } +} + +func schema_aggregator_apis_aggregation_v0alpha1_Service(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Service defines the type of service the proxied service provides.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Type is the type of service to proxy.\n\nPossible enum values:\n - `\"admission\"` maps to pluginv2.AdmissionControl\n - `\"conversion\"` maps to pluginv2.ResourceConversion\n - `\"data\"` DataSourceServiceType maps to pluginv2.Data\n - `\"datsource-proxy\"` is a reverse proxy for making requests directly to the HTTP URL specified in datasource instance settings.\n - `\"route\"` maps pluginv2.Resource\n - `\"stream\"` maps to pluginv2.Stream", + Default: "", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"admission", "conversion", "data", "datsource-proxy", "route", "stream"}, + }, + }, + "method": { + SchemaProps: spec.SchemaProps{ + Description: "Method is the HTTP method to use when proxying the service.", + Type: []string{"string"}, + Format: "", + }, + }, + "path": { + SchemaProps: spec.SchemaProps{ + Description: "Path is used by the CustomRouteServiceType and SubResourceServiceType to specify the path to the endpoint.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"type"}, + }, + }, + } +} diff --git a/pkg/aggregator/apis/aggregation/zz_generated.deepcopy.go b/pkg/aggregator/apis/aggregation/zz_generated.deepcopy.go new file mode 100644 index 00000000000..eac89dab8d9 --- /dev/null +++ b/pkg/aggregator/apis/aggregation/zz_generated.deepcopy.go @@ -0,0 +1,176 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package aggregation + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneService) DeepCopyInto(out *DataPlaneService) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneService. +func (in *DataPlaneService) DeepCopy() *DataPlaneService { + if in == nil { + return nil + } + out := new(DataPlaneService) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DataPlaneService) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneServiceCondition) DeepCopyInto(out *DataPlaneServiceCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneServiceCondition. +func (in *DataPlaneServiceCondition) DeepCopy() *DataPlaneServiceCondition { + if in == nil { + return nil + } + out := new(DataPlaneServiceCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneServiceList) DeepCopyInto(out *DataPlaneServiceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DataPlaneService, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneServiceList. +func (in *DataPlaneServiceList) DeepCopy() *DataPlaneServiceList { + if in == nil { + return nil + } + out := new(DataPlaneServiceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DataPlaneServiceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneServiceSpec) DeepCopyInto(out *DataPlaneServiceSpec) { + *out = *in + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]Service, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneServiceSpec. +func (in *DataPlaneServiceSpec) DeepCopy() *DataPlaneServiceSpec { + if in == nil { + return nil + } + out := new(DataPlaneServiceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneServiceStatus) DeepCopyInto(out *DataPlaneServiceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]DataPlaneServiceCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneServiceStatus. +func (in *DataPlaneServiceStatus) DeepCopy() *DataPlaneServiceStatus { + if in == nil { + return nil + } + out := new(DataPlaneServiceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *QueryDataResponse) DeepCopyInto(out *QueryDataResponse) { + *out = *in + out.TypeMeta = in.TypeMeta + in.QueryDataResponse.DeepCopyInto(&out.QueryDataResponse) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new QueryDataResponse. +func (in *QueryDataResponse) DeepCopy() *QueryDataResponse { + if in == nil { + return nil + } + out := new(QueryDataResponse) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *QueryDataResponse) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Service) DeepCopyInto(out *Service) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service. +func (in *Service) DeepCopy() *Service { + if in == nil { + return nil + } + out := new(Service) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/aggregator/apiserver/apiserver.go b/pkg/aggregator/apiserver/apiserver.go new file mode 100644 index 00000000000..cb144c09ab3 --- /dev/null +++ b/pkg/aggregator/apiserver/apiserver.go @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Provenance-includes-location: https://github.com/kubernetes/kube-aggregator/blob/master/pkg/apiserver/apiserver.go +// Provenance-includes-license: Apache-2.0 +// Provenance-includes-copyright: The Kubernetes Authors. + +package apiserver + +import ( + "context" + "net/http" + "time" + + "k8s.io/apimachinery/pkg/util/sets" + genericapiserver "k8s.io/apiserver/pkg/server" + serverstorage "k8s.io/apiserver/pkg/server/storage" + + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + v0alpha1helper "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1/helper" + "github.com/grafana/grafana/pkg/aggregator/apiserver/scheme" + clientset "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned" + informers "github.com/grafana/grafana/pkg/aggregator/generated/informers/externalversions" + dataplaneservicerest "github.com/grafana/grafana/pkg/aggregator/registry/dataplaneservice/rest" +) + +type ExtraConfig struct { + PluginClient PluginClient + PluginContextProvider PluginContextProvider +} + +type Config struct { + GenericConfig *genericapiserver.RecommendedConfig + ExtraConfig ExtraConfig +} + +type completedConfig struct { + GenericConfig genericapiserver.CompletedConfig + ExtraConfig *ExtraConfig +} + +// CompletedConfig same as Config, just to swap private object. +type CompletedConfig struct { + // Embed a private pointer that cannot be instantiated outside of this package. + *completedConfig +} + +type runnable interface { + RunWithContext(ctx context.Context) error +} + +// preparedGenericAPIServer is a private wrapper that enforces a call of PrepareRun() before Run can be invoked. +type preparedGrafanaAggregator struct { + *GrafanaAggregator + runnable runnable +} + +// GrafanaAggregator contains state for a Kubernetes cluster master/api server. +type GrafanaAggregator struct { + GenericAPIServer *genericapiserver.GenericAPIServer + RegistrationInformers informers.SharedInformerFactory + delegateHandler http.Handler + proxyHandlers map[string]*proxyHandler + handledGroupVersions map[string]sets.Set[string] + PluginClient PluginClient + PluginContextProvider PluginContextProvider +} + +// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. +func (cfg *Config) Complete() CompletedConfig { + c := completedConfig{ + cfg.GenericConfig.Complete(), + &cfg.ExtraConfig, + } + + c.GenericConfig.EnableDiscovery = true + + return CompletedConfig{&c} +} + +// NewWithDelegate returns a new instance of GrafanaAggregator from the given config. +func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.DelegationTarget) (*GrafanaAggregator, error) { + genericServer, err := c.GenericConfig.New("grafana-aggregator", delegationTarget) + if err != nil { + return nil, err + } + + discoveryHandler := &apisProxyHandler{ + delegationTarget: delegationTarget, + codecs: scheme.Codecs, + } + genericServer.Handler.GoRestfulContainer.Filter(discoveryHandler.handle) + + dataplaneServiceRegistrationControllerInitiated := make(chan struct{}) + if err := genericServer.RegisterMuxAndDiscoveryCompleteSignal("DataPlaneServiceRegistrationControllerInitiated", dataplaneServiceRegistrationControllerInitiated); err != nil { + return nil, err + } + + dataplaneServiceClient, err := clientset.NewForConfig(c.GenericConfig.LoopbackClientConfig) + if err != nil { + return nil, err + } + informerFactory := informers.NewSharedInformerFactory( + dataplaneServiceClient, + 5*time.Minute, + ) + + s := &GrafanaAggregator{ + GenericAPIServer: genericServer, + RegistrationInformers: informerFactory, + delegateHandler: delegationTarget.UnprotectedHandler(), + handledGroupVersions: map[string]sets.Set[string]{}, + proxyHandlers: map[string]*proxyHandler{}, + PluginClient: c.ExtraConfig.PluginClient, + PluginContextProvider: c.ExtraConfig.PluginContextProvider, + } + + dataplaneServiceRegistrationController := NewDataPlaneServiceRegistrationController(informerFactory.Aggregation().V0alpha1().DataPlaneServices(), s) + + apiGroupInfo := dataplaneservicerest.NewRESTStorage(c.GenericConfig.MergedResourceConfig, c.GenericConfig.RESTOptionsGetter, true) + if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil { + return nil, err + } + + s.GenericAPIServer.AddPostStartHookOrDie("start-dataplane-aggregator-informers", func(context genericapiserver.PostStartHookContext) error { + informerFactory.Start(context.Done()) + return nil + }) + + s.GenericAPIServer.AddPostStartHookOrDie("dataplaneservice-registration-controller", func(context genericapiserver.PostStartHookContext) error { + go dataplaneServiceRegistrationController.Run(context, dataplaneServiceRegistrationControllerInitiated) + select { + case <-context.Done(): + case <-dataplaneServiceRegistrationControllerInitiated: + } + + return nil + }) + + return s, nil +} + +// PrepareRun prepares the aggregator to run +func (s *GrafanaAggregator) PrepareRun() (preparedGrafanaAggregator, error) { + prepared := s.GenericAPIServer.PrepareRun() + return preparedGrafanaAggregator{GrafanaAggregator: s, runnable: prepared}, nil +} + +func (s preparedGrafanaAggregator) RunWithContext(ctx context.Context) error { + return s.runnable.RunWithContext(ctx) +} + +func (s *GrafanaAggregator) AddDataPlaneService(dataplaneService *v0alpha1.DataPlaneService) error { + if proxyHandler, exists := s.proxyHandlers[dataplaneService.Name]; exists { + proxyHandler.updateDataPlaneService(dataplaneService) + return nil + } + + proxyPath := "/apis/dataplane/" + dataplaneService.Spec.Group + "/" + dataplaneService.Spec.Version + proxyHandler := &proxyHandler{ + localDelegate: s.delegateHandler, + client: s.PluginClient, + pluginContextProvider: s.PluginContextProvider, + } + proxyHandler.updateDataPlaneService(dataplaneService) + s.proxyHandlers[dataplaneService.Name] = proxyHandler + s.GenericAPIServer.Handler.NonGoRestfulMux.Handle(proxyPath, proxyHandler) + s.GenericAPIServer.Handler.NonGoRestfulMux.UnlistedHandlePrefix(proxyPath+"/", proxyHandler) + + versions, exist := s.handledGroupVersions[dataplaneService.Spec.Group] + if exist { + versions.Insert(dataplaneService.Spec.Version) + return nil + } + + s.handledGroupVersions[dataplaneService.Spec.Group] = sets.New[string](dataplaneService.Spec.Version) + return nil +} + +func (s *GrafanaAggregator) RemoveDataPlaneService(dataplaneServiceName string) { + version := v0alpha1helper.DataPlaneServiceNameToGroupVersion(dataplaneServiceName) + + proxyPath := "/apis/dataplane/" + version.Group + "/" + version.Version + s.GenericAPIServer.Handler.NonGoRestfulMux.Unregister(proxyPath) + s.GenericAPIServer.Handler.NonGoRestfulMux.Unregister(proxyPath + "/") + delete(s.proxyHandlers, dataplaneServiceName) + + versions, exist := s.handledGroupVersions[version.Group] + if !exist { + return + } + versions.Delete(version.Version) + if versions.Len() > 0 { + return + } + delete(s.handledGroupVersions, version.Group) + groupPath := "/apis/dataplane/" + version.Group + s.GenericAPIServer.Handler.NonGoRestfulMux.Unregister(groupPath) + s.GenericAPIServer.Handler.NonGoRestfulMux.Unregister(groupPath + "/") +} + +// DefaultAPIResourceConfigSource returns default configuration for an APIResource. +func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig { + ret := serverstorage.NewResourceConfig() + ret.EnableVersions( + v0alpha1.SchemeGroupVersion, + ) + return ret +} diff --git a/pkg/aggregator/apiserver/dataplaneservice_controller.go b/pkg/aggregator/apiserver/dataplaneservice_controller.go new file mode 100644 index 00000000000..166cc3dbacf --- /dev/null +++ b/pkg/aggregator/apiserver/dataplaneservice_controller.go @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Provenance-includes-location: https://github.com/kubernetes/kube-aggregator/blob/master/pkg/apiserver/apiservice_controller.go +// Provenance-includes-license: Apache-2.0 +// Provenance-includes-copyright: The Kubernetes Authors. + +package apiserver + +import ( + "context" + "fmt" + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apiserver/pkg/server/dynamiccertificates" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog/v2" + + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + informers "github.com/grafana/grafana/pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1" + listers "github.com/grafana/grafana/pkg/aggregator/generated/listers/aggregation/v0alpha1" +) + +// DataPlaneHandlerManager defines the behaviour that an API handler should have. +type DataPlaneHandlerManager interface { + AddDataPlaneService(dataPlaneService *v0alpha1.DataPlaneService) error + RemoveDataPlaneService(dataPlaneServiceName string) +} + +// DataPlaneServiceRegistrationController is responsible for registering and removing API services. +type DataPlaneServiceRegistrationController struct { + dataPlaneHandlerManager DataPlaneHandlerManager + + dataPlaneServiceLister listers.DataPlaneServiceLister + dataPlaneServiceSynced cache.InformerSynced + + // To allow injection for testing. + syncFn func(key string) error + + queue workqueue.TypedRateLimitingInterface[string] +} + +var _ dynamiccertificates.Listener = &DataPlaneServiceRegistrationController{} + +// NewDataPlaneServiceRegistrationController returns a new DataPlaneServiceRegistrationController. +func NewDataPlaneServiceRegistrationController(dataPlaneServiceInformer informers.DataPlaneServiceInformer, dataPlaneHandlerManager DataPlaneHandlerManager) *DataPlaneServiceRegistrationController { + c := &DataPlaneServiceRegistrationController{ + dataPlaneHandlerManager: dataPlaneHandlerManager, + dataPlaneServiceLister: dataPlaneServiceInformer.Lister(), + dataPlaneServiceSynced: dataPlaneServiceInformer.Informer().HasSynced, + queue: workqueue.NewTypedRateLimitingQueueWithConfig( + // We want a fairly tight requeue time. The controller listens to the API, but because it relies on the routability of the + // service network, it is possible for an external, non-watchable factor to affect availability. This keeps + // the maximum disruption time to a minimum, but it does prevent hot loops. + workqueue.NewTypedItemExponentialFailureRateLimiter[string](5*time.Millisecond, 30*time.Second), + workqueue.TypedRateLimitingQueueConfig[string]{Name: "DataPlaneServiceRegistrationController"}, + ), + } + + _, err := dataPlaneServiceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: c.addDataPlaneService, + UpdateFunc: c.updateDataPlaneService, + DeleteFunc: c.deleteDataPlaneService, + }) + + if err != nil { + klog.Errorf("Failed to register event handler for DataPlaneService: %v", err) + } + + c.syncFn = c.sync + + return c +} + +func (c *DataPlaneServiceRegistrationController) sync(key string) error { + dataPlaneService, err := c.dataPlaneServiceLister.Get(key) + if apierrors.IsNotFound(err) { + c.dataPlaneHandlerManager.RemoveDataPlaneService(key) + return nil + } + if err != nil { + return err + } + + return c.dataPlaneHandlerManager.AddDataPlaneService(dataPlaneService) +} + +// Run starts DataPlaneServiceRegistrationController which will process all registration requests until stopCh is closed. +func (c *DataPlaneServiceRegistrationController) Run(ctx context.Context, handlerSyncedCh chan<- struct{}) { + defer utilruntime.HandleCrash() + defer c.queue.ShutDown() + + klog.Info("Starting DataPlaneServiceRegistrationController") + defer klog.Info("Shutting down DataPlaneServiceRegistrationController") + + if !cache.WaitForCacheSync(ctx.Done(), c.dataPlaneServiceSynced) { + return + } + + // initially sync all DataPlaneServices to make sure the proxy handler is complete + err := wait.PollUntilContextCancel(ctx, time.Second, true, func(context.Context) (bool, error) { + services, err := c.dataPlaneServiceLister.List(labels.Everything()) + if err != nil { + utilruntime.HandleError(fmt.Errorf("failed to initially list DataPlaneServices: %v", err)) + return false, nil + } + for _, s := range services { + if err := c.dataPlaneHandlerManager.AddDataPlaneService(s); err != nil { + utilruntime.HandleError(fmt.Errorf("failed to initially sync DataPlaneService %s: %v", s.Name, err)) + return false, nil + } + } + return true, nil + }) + if err != nil { + utilruntime.HandleError(err) + return + } + close(handlerSyncedCh) + + // only start one worker thread since its a slow moving API and the aggregation server adding bits + // aren't threadsafe + go wait.Until(c.runWorker, time.Second, ctx.Done()) + + <-ctx.Done() +} + +func (c *DataPlaneServiceRegistrationController) runWorker() { + for c.processNextWorkItem() { + } +} + +// processNextWorkItem deals with one key off the queue. It returns false when it's time to quit. +func (c *DataPlaneServiceRegistrationController) processNextWorkItem() bool { + key, quit := c.queue.Get() + if quit { + return false + } + defer c.queue.Done(key) + + err := c.syncFn(key) + if err == nil { + c.queue.Forget(key) + return true + } + + utilruntime.HandleError(fmt.Errorf("%v failed with : %v", key, err)) + c.queue.AddRateLimited(key) + + return true +} + +func (c *DataPlaneServiceRegistrationController) enqueueInternal(obj *v0alpha1.DataPlaneService) { + key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) + if err != nil { + klog.Errorf("Couldn't get key for object %#v: %v", obj, err) + return + } + + c.queue.Add(key) +} + +func (c *DataPlaneServiceRegistrationController) addDataPlaneService(obj interface{}) { + castObj := obj.(*v0alpha1.DataPlaneService) + klog.V(4).Infof("Adding %s", castObj.Name) + c.enqueueInternal(castObj) +} + +func (c *DataPlaneServiceRegistrationController) updateDataPlaneService(obj, _ interface{}) { + castObj := obj.(*v0alpha1.DataPlaneService) + klog.V(4).Infof("Updating %s", castObj.Name) + c.enqueueInternal(castObj) +} + +func (c *DataPlaneServiceRegistrationController) deleteDataPlaneService(obj interface{}) { + castObj, ok := obj.(*v0alpha1.DataPlaneService) + if !ok { + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if !ok { + klog.Errorf("Couldn't get object from tombstone %#v", obj) + return + } + castObj, ok = tombstone.Obj.(*v0alpha1.DataPlaneService) + if !ok { + klog.Errorf("Tombstone contained object that is not expected %#v", obj) + return + } + } + klog.V(4).Infof("Deleting %q", castObj.Name) + c.enqueueInternal(castObj) +} + +func (c *DataPlaneServiceRegistrationController) Enqueue() { + dataPlaneServices, err := c.dataPlaneServiceLister.List(labels.Everything()) + if err != nil { + utilruntime.HandleError(err) + return + } + for _, dataPlaneService := range dataPlaneServices { + c.addDataPlaneService(dataPlaneService) + } +} diff --git a/pkg/aggregator/apiserver/handler_apis.go b/pkg/aggregator/apiserver/handler_apis.go new file mode 100644 index 00000000000..11c7570decd --- /dev/null +++ b/pkg/aggregator/apiserver/handler_apis.go @@ -0,0 +1,68 @@ +package apiserver + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + + "github.com/emicklei/go-restful/v3" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" + "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" + genericapiserver "k8s.io/apiserver/pkg/server" + + aggregationv0alpha1api "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" +) + +var ( + discoveryGroup = metav1.APIGroup{ + Name: aggregationv0alpha1api.SchemeGroupVersion.Group, + Versions: []metav1.GroupVersionForDiscovery{ + { + GroupVersion: aggregationv0alpha1api.SchemeGroupVersion.String(), + Version: aggregationv0alpha1api.SchemeGroupVersion.Version, + }, + }, + PreferredVersion: metav1.GroupVersionForDiscovery{ + GroupVersion: aggregationv0alpha1api.SchemeGroupVersion.String(), + Version: aggregationv0alpha1api.SchemeGroupVersion.Version, + }, + } +) + +// apisProxyHandler serves the `/apis` endpoint. +type apisProxyHandler struct { + delegationTarget genericapiserver.DelegationTarget + codecs serializer.CodecFactory +} + +func (a *apisProxyHandler) handle(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) { + if req.Request.URL.Path != "/apis" && req.Request.URL.Path != "/apis/" { + chain.ProcessFilter(req, resp) + return + } + + discoveryGroupList := &metav1.APIGroupList{ + Groups: []metav1.APIGroup{discoveryGroup}, + } + + rw := httptest.NewRecorder() + a.delegationTarget.UnprotectedHandler().ServeHTTP(rw, req.Request) + + if rw.Code != http.StatusOK { + http.Error(resp.ResponseWriter, rw.Body.String(), rw.Code) + return + } + + proxiedGroups := metav1.APIGroupList{} + if err := json.Unmarshal(rw.Body.Bytes(), &proxiedGroups); err != nil { + http.Error(resp.ResponseWriter, err.Error(), http.StatusInternalServerError) + return + } + + discoveryGroupList.Groups = append(discoveryGroupList.Groups, proxiedGroups.Groups...) + + responsewriters.WriteObjectNegotiated(a.codecs, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, resp.ResponseWriter, req.Request, http.StatusOK, discoveryGroupList, false) +} diff --git a/pkg/aggregator/apiserver/handler_plugin.go b/pkg/aggregator/apiserver/handler_plugin.go new file mode 100644 index 00000000000..f9f47a9aa3b --- /dev/null +++ b/pkg/aggregator/apiserver/handler_plugin.go @@ -0,0 +1,141 @@ +package apiserver + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" + "k8s.io/component-base/tracing" + "k8s.io/klog/v2" + + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + grafanasemconv "github.com/grafana/grafana/pkg/semconv" +) + +type pluginHandler struct { + mux *http.ServeMux + delegate http.Handler + + client PluginClient + pluginContextProvider PluginContextProvider + + dataplaneService aggregationv0alpha1.DataPlaneService +} + +func newPluginHandler( + client PluginClient, + dataplaneService aggregationv0alpha1.DataPlaneService, + pluginContextProvider PluginContextProvider, + delegate http.Handler, +) *pluginHandler { + mux := http.NewServeMux() + h := &pluginHandler{ + mux: mux, + delegate: delegate, + client: client, + pluginContextProvider: pluginContextProvider, + dataplaneService: dataplaneService, + } + + for _, service := range dataplaneService.Spec.Services { + switch service.Type { + case aggregationv0alpha1.DataServiceType: + proxyPath := fmt.Sprintf("/apis/%s/%s/namespaces/{namespace}/connections/{uid}/query", dataplaneService.Spec.Group, dataplaneService.Spec.Version) + mux.Handle(proxyPath, h.QueryDataHandler()) + case aggregationv0alpha1.StreamServiceType: + // TODO: implement in future PR + case aggregationv0alpha1.AdmissionControlServiceType: + // TODO: implement in future PR + case aggregationv0alpha1.RouteServiceType: + // TODO: implement in future PR + case aggregationv0alpha1.ConversionServiceType: + // TODO: implement in future PR + case aggregationv0alpha1.DataSourceProxyServiceType: + // TODO: implement in future PR + } + } + + // fallback to the delegate + mux.Handle("/", delegate) + + return h +} + +func (h *pluginHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + h.mux.ServeHTTP(w, req) +} + +func (h *pluginHandler) QueryDataHandler() http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + ctx := req.Context() + span := tracing.SpanFromContext(ctx) + span.AddEvent("QueryDataHandler") + responder := &responder{w: w} + dqr := data.QueryDataRequest{} + if err := json.NewDecoder(req.Body).Decode(&dqr); err != nil { + responder.Error(w, req, err) + return + } + + dsUID := req.PathValue("uid") + dsType := h.dataplaneService.Spec.PluginID + + queries, dsRef, err := data.ToDataSourceQueries(dqr) + if err != nil { + responder.Error(w, req, err) + return + } + + // this shouldn't happen, but just in case + if dsRef == nil { + responder.Error(w, req, fmt.Errorf("missing datasource reference")) + return + } + + // the datasource type in the query body should match the plugin ID + if dsRef.Type != dsType { + err := errors.New("invalid datasource type") + klog.ErrorS(err, "type", dsType, "ref.Type", dsRef.Type) + responder.Error(w, req, err) + return + } + + // the UID in the query body should match the UID in the URL + if dsRef.UID != dsUID { + err := errors.New("invalid datasource UID") + klog.ErrorS(err, "path", dsUID, "ref.UID", dsRef.UID) + responder.Error(w, req, err) + return + } + + span.AddEvent("GetPluginContext", + grafanasemconv.GrafanaDatasourceUid(dsRef.UID), + grafanasemconv.GrafanaDatasourceType(dsRef.Type), + ) + pluginContext, err := h.pluginContextProvider.GetPluginContext(ctx, dsRef.Type, dsRef.UID) + if err != nil { + responder.Error(w, req, fmt.Errorf("unable to get plugin context: %w", err)) + return + } + + ctx = backend.WithGrafanaConfig(ctx, pluginContext.GrafanaConfig) + span.AddEvent("QueryData start", grafanasemconv.GrafanaDatasourceRequestQueryCount(len(queries))) + rsp, err := h.client.QueryData(ctx, &backend.QueryDataRequest{ + Queries: queries, + PluginContext: pluginContext, + }) + if err != nil { + responder.Error(w, req, err) + return + } + statusCode := 200 + span.AddEvent("QueryData end", semconv.HTTPResponseStatusCode(statusCode)) + responder.Object(statusCode, + &aggregationv0alpha1.QueryDataResponse{QueryDataResponse: *rsp}, + ) + } +} diff --git a/pkg/aggregator/apiserver/handler_plugin_test.go b/pkg/aggregator/apiserver/handler_plugin_test.go new file mode 100644 index 00000000000..125d4dacfc2 --- /dev/null +++ b/pkg/aggregator/apiserver/handler_plugin_test.go @@ -0,0 +1,202 @@ +package apiserver + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/data" + datav0alpha1 "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1" + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + "github.com/grafana/grafana/pkg/plugins/manager/fakes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestQueryDataHandler(t *testing.T) { + dps := v0alpha1.DataPlaneService{ + Spec: v0alpha1.DataPlaneServiceSpec{ + PluginID: "testds", + Group: "testds.example.com", + Version: "v1", + Services: []v0alpha1.Service{ + { + Type: v0alpha1.DataServiceType, + }, + }, + }, + } + + pluginContext := backend.PluginContext{ + DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ + ID: 1, + }, + } + contextProvider := &fakePluginContextProvider{ + pluginContext: pluginContext, + } + + res := &backend.QueryDataResponse{ + Responses: map[string]backend.DataResponse{ + "A": { + Frames: []*data.Frame{ + { + Name: "test-frame", + }, + }, + }, + }, + } + + pc := &fakes.FakePluginClient{ + QueryDataHandlerFunc: newfakeQueryDataHandler(res, nil), + } + + delegate := newFakeHTTPHandler(http.StatusNotFound, []byte(`Not Found`)) + handler := newPluginHandler(pc, dps, contextProvider, delegate) + + qdr := datav0alpha1.QueryDataRequest{ + TimeRange: datav0alpha1.TimeRange{}, + Queries: []datav0alpha1.DataQuery{{ + CommonQueryProperties: datav0alpha1.CommonQueryProperties{ + RefID: "1", + ResultAssertions: &datav0alpha1.ResultAssertions{}, + TimeRange: &datav0alpha1.TimeRange{}, + Datasource: &datav0alpha1.DataSourceRef{ + Type: "testds", + UID: "123", + APIVersion: "v1", + }, + DatasourceID: 0, + QueryType: "", + MaxDataPoints: 0, + IntervalMS: 0, + Hide: false, + }, + }}, + Debug: false, + } + + t.Run("should return query response", func(t *testing.T) { + buf := bytes.NewBuffer(nil) + assert.NoError(t, json.NewEncoder(buf).Encode(qdr)) + + req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/connections/123/query", buf) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + res := &v0alpha1.QueryDataResponse{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "aggregation.grafana.com/v0alpha1", + Kind: "QueryDataResponse", + }, + QueryDataResponse: *res, + } + resBuf := bytes.NewBuffer(nil) + assert.NoError(t, json.NewEncoder(resBuf).Encode(res)) + expected, err := json.MarshalIndent(res, "", " ") + require.NoError(t, err) + assert.Equal(t, string(expected), rr.Body.String()) + }) + + t.Run("should return type error", func(t *testing.T) { + qdr.Queries[0].Datasource.Type = "wrongds" + buf := bytes.NewBuffer(nil) + assert.NoError(t, json.NewEncoder(buf).Encode(qdr)) + + req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/connections/123/query", buf) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusInternalServerError, rr.Code) + res := &metav1.Status{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Status", + }, + Status: metav1.StatusFailure, + Code: http.StatusInternalServerError, + Message: "invalid datasource type", + } + resBuf := bytes.NewBuffer(nil) + assert.NoError(t, json.NewEncoder(resBuf).Encode(res)) + expected, err := json.MarshalIndent(res, "", " ") + require.NoError(t, err) + assert.Equal(t, string(expected), rr.Body.String()) + }) + + t.Run("should return UID error", func(t *testing.T) { + qdr.Queries[0].Datasource.Type = "testds" + buf := bytes.NewBuffer(nil) + assert.NoError(t, json.NewEncoder(buf).Encode(qdr)) + + req, err := http.NewRequest("POST", "/apis/testds.example.com/v1/namespaces/default/connections/abc/query", buf) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusInternalServerError, rr.Code) + res := &metav1.Status{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Status", + }, + Status: metav1.StatusFailure, + Code: http.StatusInternalServerError, + Message: "invalid datasource UID", + } + resBuf := bytes.NewBuffer(nil) + assert.NoError(t, json.NewEncoder(resBuf).Encode(res)) + expected, err := json.MarshalIndent(res, "", " ") + require.NoError(t, err) + assert.Equal(t, string(expected), rr.Body.String()) + }) + + t.Run("should return delegate response if group does not match", func(t *testing.T) { + req, err := http.NewRequest("POST", "/apis/wrongds.example.com/v1/namespaces/default/connections/abc/query", bytes.NewBuffer(nil)) + assert.NoError(t, err) + + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + + assert.Equal(t, http.StatusNotFound, rr.Code) + assert.Equal(t, "Not Found", rr.Body.String()) + }) +} + +type fakePluginContextProvider struct { + pluginContext backend.PluginContext + err error +} + +func (f fakePluginContextProvider) GetPluginContext(ctx context.Context, pluginID, dsUID string) (backend.PluginContext, error) { + return f.pluginContext, f.err +} + +func newfakeQueryDataHandler(res *backend.QueryDataResponse, err error) backend.QueryDataHandlerFunc { + return func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { + return res, err + } +} + +func newFakeHTTPHandler(status int, res []byte) http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + w.WriteHeader(status) + _, err := w.Write(res) + if err != nil { + panic(err) + } + } +} diff --git a/pkg/aggregator/apiserver/handler_proxy.go b/pkg/aggregator/apiserver/handler_proxy.go new file mode 100644 index 00000000000..1000d457082 --- /dev/null +++ b/pkg/aggregator/apiserver/handler_proxy.go @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Provenance-includes-location: https://github.com/kubernetes/kube-aggregator/blob/master/pkg/apiserver/handler_proxy.go +// Provenance-includes-license: Apache-2.0 +// Provenance-includes-copyright: The Kubernetes Authors. + +package apiserver + +import ( + "context" + "net/http" + "sync/atomic" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/component-base/tracing" + + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + grafanasemconv "github.com/grafana/grafana/pkg/semconv" +) + +type PluginClient interface { + backend.QueryDataHandler + backend.StreamHandler + backend.AdmissionHandler + backend.CallResourceHandler +} + +type PluginContextProvider interface { + GetPluginContext(ctx context.Context, pluginID, uid string) (backend.PluginContext, error) +} + +// proxyHandler provides a http.Handler which will proxy traffic to a plugin client. +type proxyHandler struct { + localDelegate http.Handler + client PluginClient + pluginContextProvider PluginContextProvider + handlingInfo atomic.Value +} + +type proxyHandlingInfo struct { + name string + handler *pluginHandler +} + +func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + value := r.handlingInfo.Load() + if value == nil { + r.localDelegate.ServeHTTP(w, req) + return + } + handlingInfo := value.(proxyHandlingInfo) + + namespace, _ := request.NamespaceFrom(req.Context()) + ctx, span := tracing.Start( + req.Context(), + "grafana-aggregator", + grafanasemconv.K8sDataplaneserviceName(handlingInfo.name), + semconv.K8SNamespaceName(namespace), + semconv.HTTPMethod(req.Method), + semconv.HTTPURL(req.URL.String()), + ) + // log if the span has not ended after a minute + defer span.End(time.Minute) + + handlingInfo.handler.ServeHTTP(w, req.WithContext(ctx)) +} + +func (r *proxyHandler) updateDataPlaneService(dataplaneService *aggregationv0alpha1.DataPlaneService) { + newInfo := proxyHandlingInfo{ + name: dataplaneService.Name, + } + + newInfo.handler = newPluginHandler( + r.client, + *dataplaneService, + r.pluginContextProvider, + r.localDelegate, + ) + + r.handlingInfo.Store(newInfo) +} + +// responder implements rest.Responder for assisting a connector in writing objects or errors. +type responder struct { + w http.ResponseWriter +} + +// TODO this should properly handle content type negotiation +// if the caller asked for protobuf and you write JSON bad things happen. +func (r *responder) Object(statusCode int, obj runtime.Object) { + responsewriters.WriteRawJSON(statusCode, obj, r.w) +} + +func (r *responder) Error(_ http.ResponseWriter, req *http.Request, err error) { + tracing.SpanFromContext(req.Context()).RecordError(err) + s := responsewriters.ErrorToAPIStatus(err) + r.Object(http.StatusInternalServerError, s) +} diff --git a/pkg/aggregator/apiserver/scheme/scheme.go b/pkg/aggregator/apiserver/scheme/scheme.go new file mode 100644 index 00000000000..b1089e5c9a7 --- /dev/null +++ b/pkg/aggregator/apiserver/scheme/scheme.go @@ -0,0 +1,32 @@ +package scheme + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/install" +) + +var ( + Scheme = runtime.NewScheme() + Codecs = serializer.NewCodecFactory(Scheme) +) + +func init() { + // we need to add the options to empty v1 + // TODO fix the server code to avoid this + metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + + // TODO: keep the generic API server from wanting this + unversioned := schema.GroupVersion{Group: "", Version: "v1"} + Scheme.AddUnversionedTypes(unversioned, + &metav1.Status{}, + &metav1.APIVersions{}, + &metav1.APIGroupList{}, + &metav1.APIGroup{}, + &metav1.APIResourceList{}, + ) + install.Install(Scheme) +} diff --git a/pkg/aggregator/examples/prometheus.yml b/pkg/aggregator/examples/prometheus.yml new file mode 100644 index 00000000000..44379aec765 --- /dev/null +++ b/pkg/aggregator/examples/prometheus.yml @@ -0,0 +1,9 @@ +apiVersion: aggregation.grafana.app/v0alpha1 +kind: DataPlaneService +metadata: + name: v0alpha1.prometheus.grafana.app +spec: + group: prometheus.grafana.app + version: v0alpha1 + services: + - type: data diff --git a/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservice.go b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservice.go new file mode 100644 index 00000000000..b62f426821a --- /dev/null +++ b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservice.go @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// DataPlaneServiceApplyConfiguration represents an declarative configuration of the DataPlaneService type for use +// with apply. +type DataPlaneServiceApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *DataPlaneServiceSpecApplyConfiguration `json:"spec,omitempty"` + Status *DataPlaneServiceStatusApplyConfiguration `json:"status,omitempty"` +} + +// DataPlaneService constructs an declarative configuration of the DataPlaneService type for use with +// apply. +func DataPlaneService(name string) *DataPlaneServiceApplyConfiguration { + b := &DataPlaneServiceApplyConfiguration{} + b.WithName(name) + b.WithKind("DataPlaneService") + b.WithAPIVersion("aggregation.grafana.app/v0alpha1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithKind(value string) *DataPlaneServiceApplyConfiguration { + b.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithAPIVersion(value string) *DataPlaneServiceApplyConfiguration { + b.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithName(value string) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithGenerateName(value string) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithNamespace(value string) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithUID(value types.UID) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithResourceVersion(value string) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithGeneration(value int64) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithCreationTimestamp(value metav1.Time) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *DataPlaneServiceApplyConfiguration) WithLabels(entries map[string]string) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Labels == nil && len(entries) > 0 { + b.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *DataPlaneServiceApplyConfiguration) WithAnnotations(entries map[string]string) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Annotations == nil && len(entries) > 0 { + b.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *DataPlaneServiceApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.OwnerReferences = append(b.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *DataPlaneServiceApplyConfiguration) WithFinalizers(values ...string) *DataPlaneServiceApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.Finalizers = append(b.Finalizers, values[i]) + } + return b +} + +func (b *DataPlaneServiceApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithSpec(value *DataPlaneServiceSpecApplyConfiguration) *DataPlaneServiceApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *DataPlaneServiceApplyConfiguration) WithStatus(value *DataPlaneServiceStatusApplyConfiguration) *DataPlaneServiceApplyConfiguration { + b.Status = value + return b +} diff --git a/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicecondition.go b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicecondition.go new file mode 100644 index 00000000000..feaf7e123e5 --- /dev/null +++ b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicecondition.go @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// DataPlaneServiceConditionApplyConfiguration represents an declarative configuration of the DataPlaneServiceCondition type for use +// with apply. +type DataPlaneServiceConditionApplyConfiguration struct { + Type *v0alpha1.DataPlaneServiceConditionType `json:"type,omitempty"` + Status *v0alpha1.ConditionStatus `json:"status,omitempty"` + LastTransitionTime *v1.Time `json:"lastTransitionTime,omitempty"` + Reason *string `json:"reason,omitempty"` + Message *string `json:"message,omitempty"` +} + +// DataPlaneServiceConditionApplyConfiguration constructs an declarative configuration of the DataPlaneServiceCondition type for use with +// apply. +func DataPlaneServiceCondition() *DataPlaneServiceConditionApplyConfiguration { + return &DataPlaneServiceConditionApplyConfiguration{} +} + +// WithType sets the Type field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Type field is set to the value of the last call. +func (b *DataPlaneServiceConditionApplyConfiguration) WithType(value v0alpha1.DataPlaneServiceConditionType) *DataPlaneServiceConditionApplyConfiguration { + b.Type = &value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *DataPlaneServiceConditionApplyConfiguration) WithStatus(value v0alpha1.ConditionStatus) *DataPlaneServiceConditionApplyConfiguration { + b.Status = &value + return b +} + +// WithLastTransitionTime sets the LastTransitionTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastTransitionTime field is set to the value of the last call. +func (b *DataPlaneServiceConditionApplyConfiguration) WithLastTransitionTime(value v1.Time) *DataPlaneServiceConditionApplyConfiguration { + b.LastTransitionTime = &value + return b +} + +// WithReason sets the Reason field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Reason field is set to the value of the last call. +func (b *DataPlaneServiceConditionApplyConfiguration) WithReason(value string) *DataPlaneServiceConditionApplyConfiguration { + b.Reason = &value + return b +} + +// WithMessage sets the Message field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Message field is set to the value of the last call. +func (b *DataPlaneServiceConditionApplyConfiguration) WithMessage(value string) *DataPlaneServiceConditionApplyConfiguration { + b.Message = &value + return b +} diff --git a/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicespec.go b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicespec.go new file mode 100644 index 00000000000..fdac3efd8c0 --- /dev/null +++ b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicespec.go @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" +) + +// DataPlaneServiceSpecApplyConfiguration represents an declarative configuration of the DataPlaneServiceSpec type for use +// with apply. +type DataPlaneServiceSpecApplyConfiguration struct { + PluginID *string `json:"pluginID,omitempty"` + PluginType *v0alpha1.PluginType `json:"pluginType,omitempty"` + Group *string `json:"group,omitempty"` + Version *string `json:"version,omitempty"` + Services []ServiceApplyConfiguration `json:"services,omitempty"` +} + +// DataPlaneServiceSpecApplyConfiguration constructs an declarative configuration of the DataPlaneServiceSpec type for use with +// apply. +func DataPlaneServiceSpec() *DataPlaneServiceSpecApplyConfiguration { + return &DataPlaneServiceSpecApplyConfiguration{} +} + +// WithPluginID sets the PluginID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PluginID field is set to the value of the last call. +func (b *DataPlaneServiceSpecApplyConfiguration) WithPluginID(value string) *DataPlaneServiceSpecApplyConfiguration { + b.PluginID = &value + return b +} + +// WithPluginType sets the PluginType field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PluginType field is set to the value of the last call. +func (b *DataPlaneServiceSpecApplyConfiguration) WithPluginType(value v0alpha1.PluginType) *DataPlaneServiceSpecApplyConfiguration { + b.PluginType = &value + return b +} + +// WithGroup sets the Group field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Group field is set to the value of the last call. +func (b *DataPlaneServiceSpecApplyConfiguration) WithGroup(value string) *DataPlaneServiceSpecApplyConfiguration { + b.Group = &value + return b +} + +// WithVersion sets the Version field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Version field is set to the value of the last call. +func (b *DataPlaneServiceSpecApplyConfiguration) WithVersion(value string) *DataPlaneServiceSpecApplyConfiguration { + b.Version = &value + return b +} + +// WithServices adds the given value to the Services field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Services field. +func (b *DataPlaneServiceSpecApplyConfiguration) WithServices(values ...*ServiceApplyConfiguration) *DataPlaneServiceSpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithServices") + } + b.Services = append(b.Services, *values[i]) + } + return b +} diff --git a/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicestatus.go b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicestatus.go new file mode 100644 index 00000000000..ca6a99c259c --- /dev/null +++ b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/dataplaneservicestatus.go @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +// DataPlaneServiceStatusApplyConfiguration represents an declarative configuration of the DataPlaneServiceStatus type for use +// with apply. +type DataPlaneServiceStatusApplyConfiguration struct { + Conditions []DataPlaneServiceConditionApplyConfiguration `json:"conditions,omitempty"` +} + +// DataPlaneServiceStatusApplyConfiguration constructs an declarative configuration of the DataPlaneServiceStatus type for use with +// apply. +func DataPlaneServiceStatus() *DataPlaneServiceStatusApplyConfiguration { + return &DataPlaneServiceStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *DataPlaneServiceStatusApplyConfiguration) WithConditions(values ...*DataPlaneServiceConditionApplyConfiguration) *DataPlaneServiceStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} diff --git a/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/service.go b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/service.go new file mode 100644 index 00000000000..a585f271dd6 --- /dev/null +++ b/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1/service.go @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" +) + +// ServiceApplyConfiguration represents an declarative configuration of the Service type for use +// with apply. +type ServiceApplyConfiguration struct { + Type *v0alpha1.ServiceType `json:"type,omitempty"` + Method *string `json:"method,omitempty"` + Path *string `json:"path,omitempty"` +} + +// ServiceApplyConfiguration constructs an declarative configuration of the Service type for use with +// apply. +func Service() *ServiceApplyConfiguration { + return &ServiceApplyConfiguration{} +} + +// WithType sets the Type field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Type field is set to the value of the last call. +func (b *ServiceApplyConfiguration) WithType(value v0alpha1.ServiceType) *ServiceApplyConfiguration { + b.Type = &value + return b +} + +// WithMethod sets the Method field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Method field is set to the value of the last call. +func (b *ServiceApplyConfiguration) WithMethod(value string) *ServiceApplyConfiguration { + b.Method = &value + return b +} + +// WithPath sets the Path field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Path field is set to the value of the last call. +func (b *ServiceApplyConfiguration) WithPath(value string) *ServiceApplyConfiguration { + b.Path = &value + return b +} diff --git a/pkg/aggregator/generated/applyconfiguration/internal/internal.go b/pkg/aggregator/generated/applyconfiguration/internal/internal.go new file mode 100644 index 00000000000..2329c80fe2d --- /dev/null +++ b/pkg/aggregator/generated/applyconfiguration/internal/internal.go @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package internal + +import ( + "fmt" + "sync" + + typed "sigs.k8s.io/structured-merge-diff/v4/typed" +) + +func Parser() *typed.Parser { + parserOnce.Do(func() { + var err error + parser, err = typed.NewParser(schemaYAML) + if err != nil { + panic(fmt.Sprintf("Failed to parse schema: %v", err)) + } + }) + return parser +} + +var parserOnce sync.Once +var parser *typed.Parser +var schemaYAML = typed.YAMLObject(`types: +- name: __untyped_atomic_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic +- name: __untyped_deduced_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_deduced_ + elementRelationship: separable +`) diff --git a/pkg/aggregator/generated/applyconfiguration/utils.go b/pkg/aggregator/generated/applyconfiguration/utils.go new file mode 100644 index 00000000000..dd9c27d23ca --- /dev/null +++ b/pkg/aggregator/generated/applyconfiguration/utils.go @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package applyconfiguration + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1" + schema "k8s.io/apimachinery/pkg/runtime/schema" +) + +// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no +// apply configuration type exists for the given GroupVersionKind. +func ForKind(kind schema.GroupVersionKind) interface{} { + switch kind { + // Group=aggregation.grafana.app, Version=v0alpha1 + case v0alpha1.SchemeGroupVersion.WithKind("DataPlaneService"): + return &aggregationv0alpha1.DataPlaneServiceApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("DataPlaneServiceCondition"): + return &aggregationv0alpha1.DataPlaneServiceConditionApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("DataPlaneServiceSpec"): + return &aggregationv0alpha1.DataPlaneServiceSpecApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("DataPlaneServiceStatus"): + return &aggregationv0alpha1.DataPlaneServiceStatusApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("Service"): + return &aggregationv0alpha1.ServiceApplyConfiguration{} + + } + return nil +} diff --git a/pkg/aggregator/generated/clientset/versioned/clientset.go b/pkg/aggregator/generated/clientset/versioned/clientset.go new file mode 100644 index 00000000000..b800a11ee97 --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/clientset.go @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + "fmt" + "net/http" + + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1" + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + AggregationV0alpha1() aggregationv0alpha1.AggregationV0alpha1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + aggregationV0alpha1 *aggregationv0alpha1.AggregationV0alpha1Client +} + +// AggregationV0alpha1 retrieves the AggregationV0alpha1Client +func (c *Clientset) AggregationV0alpha1() aggregationv0alpha1.AggregationV0alpha1Interface { + return c.aggregationV0alpha1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.aggregationV0alpha1, err = aggregationv0alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.aggregationV0alpha1 = aggregationv0alpha1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/pkg/aggregator/generated/clientset/versioned/fake/clientset_generated.go b/pkg/aggregator/generated/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 00000000000..b0cc69a076e --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + clientset "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned" + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1" + fakeaggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// AggregationV0alpha1 retrieves the AggregationV0alpha1Client +func (c *Clientset) AggregationV0alpha1() aggregationv0alpha1.AggregationV0alpha1Interface { + return &fakeaggregationv0alpha1.FakeAggregationV0alpha1{Fake: &c.Fake} +} diff --git a/pkg/aggregator/generated/clientset/versioned/fake/doc.go b/pkg/aggregator/generated/clientset/versioned/fake/doc.go new file mode 100644 index 00000000000..bc6b017db1b --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/fake/doc.go @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/pkg/aggregator/generated/clientset/versioned/fake/register.go b/pkg/aggregator/generated/clientset/versioned/fake/register.go new file mode 100644 index 00000000000..58077ce58e3 --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/fake/register.go @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + aggregationv0alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/pkg/aggregator/generated/clientset/versioned/scheme/doc.go b/pkg/aggregator/generated/clientset/versioned/scheme/doc.go new file mode 100644 index 00000000000..b69e1aef906 --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/scheme/doc.go @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/pkg/aggregator/generated/clientset/versioned/scheme/register.go b/pkg/aggregator/generated/clientset/versioned/scheme/register.go new file mode 100644 index 00000000000..4f83ad6664d --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/scheme/register.go @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + aggregationv0alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/aggregation_client.go b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/aggregation_client.go new file mode 100644 index 00000000000..e630a11aae7 --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/aggregation_client.go @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + "net/http" + + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned/scheme" + rest "k8s.io/client-go/rest" +) + +type AggregationV0alpha1Interface interface { + RESTClient() rest.Interface + DataPlaneServicesGetter +} + +// AggregationV0alpha1Client is used to interact with features provided by the aggregation.grafana.app group. +type AggregationV0alpha1Client struct { + restClient rest.Interface +} + +func (c *AggregationV0alpha1Client) DataPlaneServices() DataPlaneServiceInterface { + return newDataPlaneServices(c) +} + +// NewForConfig creates a new AggregationV0alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*AggregationV0alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new AggregationV0alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*AggregationV0alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &AggregationV0alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new AggregationV0alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *AggregationV0alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new AggregationV0alpha1Client for the given RESTClient. +func New(c rest.Interface) *AggregationV0alpha1Client { + return &AggregationV0alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v0alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *AggregationV0alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/dataplaneservice.go b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/dataplaneservice.go new file mode 100644 index 00000000000..311f6a77285 --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/dataplaneservice.go @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + "context" + json "encoding/json" + "fmt" + "time" + + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1" + scheme "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// DataPlaneServicesGetter has a method to return a DataPlaneServiceInterface. +// A group's client should implement this interface. +type DataPlaneServicesGetter interface { + DataPlaneServices() DataPlaneServiceInterface +} + +// DataPlaneServiceInterface has methods to work with DataPlaneService resources. +type DataPlaneServiceInterface interface { + Create(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.CreateOptions) (*v0alpha1.DataPlaneService, error) + Update(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.UpdateOptions) (*v0alpha1.DataPlaneService, error) + UpdateStatus(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.UpdateOptions) (*v0alpha1.DataPlaneService, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v0alpha1.DataPlaneService, error) + List(ctx context.Context, opts v1.ListOptions) (*v0alpha1.DataPlaneServiceList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v0alpha1.DataPlaneService, err error) + Apply(ctx context.Context, dataPlaneService *aggregationv0alpha1.DataPlaneServiceApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.DataPlaneService, err error) + ApplyStatus(ctx context.Context, dataPlaneService *aggregationv0alpha1.DataPlaneServiceApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.DataPlaneService, err error) + DataPlaneServiceExpansion +} + +// dataPlaneServices implements DataPlaneServiceInterface +type dataPlaneServices struct { + client rest.Interface +} + +// newDataPlaneServices returns a DataPlaneServices +func newDataPlaneServices(c *AggregationV0alpha1Client) *dataPlaneServices { + return &dataPlaneServices{ + client: c.RESTClient(), + } +} + +// Get takes name of the dataPlaneService, and returns the corresponding dataPlaneService object, and an error if there is any. +func (c *dataPlaneServices) Get(ctx context.Context, name string, options v1.GetOptions) (result *v0alpha1.DataPlaneService, err error) { + result = &v0alpha1.DataPlaneService{} + err = c.client.Get(). + Resource("dataplaneservices"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of DataPlaneServices that match those selectors. +func (c *dataPlaneServices) List(ctx context.Context, opts v1.ListOptions) (result *v0alpha1.DataPlaneServiceList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v0alpha1.DataPlaneServiceList{} + err = c.client.Get(). + Resource("dataplaneservices"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested dataPlaneServices. +func (c *dataPlaneServices) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("dataplaneservices"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a dataPlaneService and creates it. Returns the server's representation of the dataPlaneService, and an error, if there is any. +func (c *dataPlaneServices) Create(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.CreateOptions) (result *v0alpha1.DataPlaneService, err error) { + result = &v0alpha1.DataPlaneService{} + err = c.client.Post(). + Resource("dataplaneservices"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(dataPlaneService). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a dataPlaneService and updates it. Returns the server's representation of the dataPlaneService, and an error, if there is any. +func (c *dataPlaneServices) Update(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.UpdateOptions) (result *v0alpha1.DataPlaneService, err error) { + result = &v0alpha1.DataPlaneService{} + err = c.client.Put(). + Resource("dataplaneservices"). + Name(dataPlaneService.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(dataPlaneService). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *dataPlaneServices) UpdateStatus(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.UpdateOptions) (result *v0alpha1.DataPlaneService, err error) { + result = &v0alpha1.DataPlaneService{} + err = c.client.Put(). + Resource("dataplaneservices"). + Name(dataPlaneService.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(dataPlaneService). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the dataPlaneService and deletes it. Returns an error if one occurs. +func (c *dataPlaneServices) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("dataplaneservices"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *dataPlaneServices) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("dataplaneservices"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched dataPlaneService. +func (c *dataPlaneServices) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v0alpha1.DataPlaneService, err error) { + result = &v0alpha1.DataPlaneService{} + err = c.client.Patch(pt). + Resource("dataplaneservices"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied dataPlaneService. +func (c *dataPlaneServices) Apply(ctx context.Context, dataPlaneService *aggregationv0alpha1.DataPlaneServiceApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.DataPlaneService, err error) { + if dataPlaneService == nil { + return nil, fmt.Errorf("dataPlaneService provided to Apply must not be nil") + } + patchOpts := opts.ToPatchOptions() + data, err := json.Marshal(dataPlaneService) + if err != nil { + return nil, err + } + name := dataPlaneService.Name + if name == nil { + return nil, fmt.Errorf("dataPlaneService.Name must be provided to Apply") + } + result = &v0alpha1.DataPlaneService{} + err = c.client.Patch(types.ApplyPatchType). + Resource("dataplaneservices"). + Name(*name). + VersionedParams(&patchOpts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *dataPlaneServices) ApplyStatus(ctx context.Context, dataPlaneService *aggregationv0alpha1.DataPlaneServiceApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.DataPlaneService, err error) { + if dataPlaneService == nil { + return nil, fmt.Errorf("dataPlaneService provided to Apply must not be nil") + } + patchOpts := opts.ToPatchOptions() + data, err := json.Marshal(dataPlaneService) + if err != nil { + return nil, err + } + + name := dataPlaneService.Name + if name == nil { + return nil, fmt.Errorf("dataPlaneService.Name must be provided to Apply") + } + + result = &v0alpha1.DataPlaneService{} + err = c.client.Patch(types.ApplyPatchType). + Resource("dataplaneservices"). + Name(*name). + SubResource("status"). + VersionedParams(&patchOpts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/doc.go b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/doc.go new file mode 100644 index 00000000000..1c86744fecc --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/doc.go @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v0alpha1 diff --git a/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/doc.go b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/doc.go new file mode 100644 index 00000000000..d96b985b3ea --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/doc.go @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/fake_aggregation_client.go b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/fake_aggregation_client.go new file mode 100644 index 00000000000..3c6e52ddd95 --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/fake_aggregation_client.go @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAggregationV0alpha1 struct { + *testing.Fake +} + +func (c *FakeAggregationV0alpha1) DataPlaneServices() v0alpha1.DataPlaneServiceInterface { + return &FakeDataPlaneServices{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAggregationV0alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/fake_dataplaneservice.go b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/fake_dataplaneservice.go new file mode 100644 index 00000000000..0c323038118 --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/fake/fake_dataplaneservice.go @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + json "encoding/json" + "fmt" + + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/applyconfiguration/aggregation/v0alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeDataPlaneServices implements DataPlaneServiceInterface +type FakeDataPlaneServices struct { + Fake *FakeAggregationV0alpha1 +} + +var dataplaneservicesResource = v0alpha1.SchemeGroupVersion.WithResource("dataplaneservices") + +var dataplaneservicesKind = v0alpha1.SchemeGroupVersion.WithKind("DataPlaneService") + +// Get takes name of the dataPlaneService, and returns the corresponding dataPlaneService object, and an error if there is any. +func (c *FakeDataPlaneServices) Get(ctx context.Context, name string, options v1.GetOptions) (result *v0alpha1.DataPlaneService, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(dataplaneservicesResource, name), &v0alpha1.DataPlaneService{}) + if obj == nil { + return nil, err + } + return obj.(*v0alpha1.DataPlaneService), err +} + +// List takes label and field selectors, and returns the list of DataPlaneServices that match those selectors. +func (c *FakeDataPlaneServices) List(ctx context.Context, opts v1.ListOptions) (result *v0alpha1.DataPlaneServiceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(dataplaneservicesResource, dataplaneservicesKind, opts), &v0alpha1.DataPlaneServiceList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v0alpha1.DataPlaneServiceList{ListMeta: obj.(*v0alpha1.DataPlaneServiceList).ListMeta} + for _, item := range obj.(*v0alpha1.DataPlaneServiceList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested dataPlaneServices. +func (c *FakeDataPlaneServices) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(dataplaneservicesResource, opts)) +} + +// Create takes the representation of a dataPlaneService and creates it. Returns the server's representation of the dataPlaneService, and an error, if there is any. +func (c *FakeDataPlaneServices) Create(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.CreateOptions) (result *v0alpha1.DataPlaneService, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(dataplaneservicesResource, dataPlaneService), &v0alpha1.DataPlaneService{}) + if obj == nil { + return nil, err + } + return obj.(*v0alpha1.DataPlaneService), err +} + +// Update takes the representation of a dataPlaneService and updates it. Returns the server's representation of the dataPlaneService, and an error, if there is any. +func (c *FakeDataPlaneServices) Update(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.UpdateOptions) (result *v0alpha1.DataPlaneService, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(dataplaneservicesResource, dataPlaneService), &v0alpha1.DataPlaneService{}) + if obj == nil { + return nil, err + } + return obj.(*v0alpha1.DataPlaneService), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDataPlaneServices) UpdateStatus(ctx context.Context, dataPlaneService *v0alpha1.DataPlaneService, opts v1.UpdateOptions) (*v0alpha1.DataPlaneService, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(dataplaneservicesResource, "status", dataPlaneService), &v0alpha1.DataPlaneService{}) + if obj == nil { + return nil, err + } + return obj.(*v0alpha1.DataPlaneService), err +} + +// Delete takes name of the dataPlaneService and deletes it. Returns an error if one occurs. +func (c *FakeDataPlaneServices) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(dataplaneservicesResource, name, opts), &v0alpha1.DataPlaneService{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDataPlaneServices) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(dataplaneservicesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v0alpha1.DataPlaneServiceList{}) + return err +} + +// Patch applies the patch and returns the patched dataPlaneService. +func (c *FakeDataPlaneServices) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v0alpha1.DataPlaneService, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(dataplaneservicesResource, name, pt, data, subresources...), &v0alpha1.DataPlaneService{}) + if obj == nil { + return nil, err + } + return obj.(*v0alpha1.DataPlaneService), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied dataPlaneService. +func (c *FakeDataPlaneServices) Apply(ctx context.Context, dataPlaneService *aggregationv0alpha1.DataPlaneServiceApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.DataPlaneService, err error) { + if dataPlaneService == nil { + return nil, fmt.Errorf("dataPlaneService provided to Apply must not be nil") + } + data, err := json.Marshal(dataPlaneService) + if err != nil { + return nil, err + } + name := dataPlaneService.Name + if name == nil { + return nil, fmt.Errorf("dataPlaneService.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(dataplaneservicesResource, *name, types.ApplyPatchType, data), &v0alpha1.DataPlaneService{}) + if obj == nil { + return nil, err + } + return obj.(*v0alpha1.DataPlaneService), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeDataPlaneServices) ApplyStatus(ctx context.Context, dataPlaneService *aggregationv0alpha1.DataPlaneServiceApplyConfiguration, opts v1.ApplyOptions) (result *v0alpha1.DataPlaneService, err error) { + if dataPlaneService == nil { + return nil, fmt.Errorf("dataPlaneService provided to Apply must not be nil") + } + data, err := json.Marshal(dataPlaneService) + if err != nil { + return nil, err + } + name := dataPlaneService.Name + if name == nil { + return nil, fmt.Errorf("dataPlaneService.Name must be provided to Apply") + } + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(dataplaneservicesResource, *name, types.ApplyPatchType, data, "status"), &v0alpha1.DataPlaneService{}) + if obj == nil { + return nil, err + } + return obj.(*v0alpha1.DataPlaneService), err +} diff --git a/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/generated_expansion.go b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/generated_expansion.go new file mode 100644 index 00000000000..56fd84a8795 --- /dev/null +++ b/pkg/aggregator/generated/clientset/versioned/typed/aggregation/v0alpha1/generated_expansion.go @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by client-gen. DO NOT EDIT. + +package v0alpha1 + +type DataPlaneServiceExpansion interface{} diff --git a/pkg/aggregator/generated/informers/externalversions/aggregation/interface.go b/pkg/aggregator/generated/informers/externalversions/aggregation/interface.go new file mode 100644 index 00000000000..f9ccd473371 --- /dev/null +++ b/pkg/aggregator/generated/informers/externalversions/aggregation/interface.go @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package aggregation + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1" + internalinterfaces "github.com/grafana/grafana/pkg/aggregator/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V0alpha1 provides access to shared informers for resources in V0alpha1. + V0alpha1() v0alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V0alpha1 returns a new v0alpha1.Interface. +func (g *group) V0alpha1() v0alpha1.Interface { + return v0alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1/dataplaneservice.go b/pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1/dataplaneservice.go new file mode 100644 index 00000000000..cc17b9ac758 --- /dev/null +++ b/pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1/dataplaneservice.go @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + "context" + time "time" + + aggregationv0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + versioned "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned" + internalinterfaces "github.com/grafana/grafana/pkg/aggregator/generated/informers/externalversions/internalinterfaces" + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/generated/listers/aggregation/v0alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// DataPlaneServiceInformer provides access to a shared informer and lister for +// DataPlaneServices. +type DataPlaneServiceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v0alpha1.DataPlaneServiceLister +} + +type dataPlaneServiceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewDataPlaneServiceInformer constructs a new informer for DataPlaneService type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewDataPlaneServiceInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredDataPlaneServiceInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredDataPlaneServiceInformer constructs a new informer for DataPlaneService type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredDataPlaneServiceInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.AggregationV0alpha1().DataPlaneServices().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.AggregationV0alpha1().DataPlaneServices().Watch(context.TODO(), options) + }, + }, + &aggregationv0alpha1.DataPlaneService{}, + resyncPeriod, + indexers, + ) +} + +func (f *dataPlaneServiceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredDataPlaneServiceInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *dataPlaneServiceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&aggregationv0alpha1.DataPlaneService{}, f.defaultInformer) +} + +func (f *dataPlaneServiceInformer) Lister() v0alpha1.DataPlaneServiceLister { + return v0alpha1.NewDataPlaneServiceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1/interface.go b/pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1/interface.go new file mode 100644 index 00000000000..94bfe874e46 --- /dev/null +++ b/pkg/aggregator/generated/informers/externalversions/aggregation/v0alpha1/interface.go @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + internalinterfaces "github.com/grafana/grafana/pkg/aggregator/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // DataPlaneServices returns a DataPlaneServiceInformer. + DataPlaneServices() DataPlaneServiceInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// DataPlaneServices returns a DataPlaneServiceInformer. +func (v *version) DataPlaneServices() DataPlaneServiceInformer { + return &dataPlaneServiceInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/aggregator/generated/informers/externalversions/factory.go b/pkg/aggregator/generated/informers/externalversions/factory.go new file mode 100644 index 00000000000..300863eaae0 --- /dev/null +++ b/pkg/aggregator/generated/informers/externalversions/factory.go @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + versioned "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned" + aggregation "github.com/grafana/grafana/pkg/aggregator/generated/informers/externalversions/aggregation" + internalinterfaces "github.com/grafana/grafana/pkg/aggregator/generated/informers/externalversions/internalinterfaces" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + transform cache.TransformFunc + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform cache.TransformFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + Aggregation() aggregation.Interface +} + +func (f *sharedInformerFactory) Aggregation() aggregation.Interface { + return aggregation.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/aggregator/generated/informers/externalversions/generic.go b/pkg/aggregator/generated/informers/externalversions/generic.go new file mode 100644 index 00000000000..3df2c0067b0 --- /dev/null +++ b/pkg/aggregator/generated/informers/externalversions/generic.go @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=aggregation.grafana.app, Version=v0alpha1 + case v0alpha1.SchemeGroupVersion.WithResource("dataplaneservices"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Aggregation().V0alpha1().DataPlaneServices().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/pkg/aggregator/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/aggregator/generated/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 00000000000..ab740d9ee31 --- /dev/null +++ b/pkg/aggregator/generated/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + versioned "github.com/grafana/grafana/pkg/aggregator/generated/clientset/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/pkg/aggregator/generated/listers/aggregation/v0alpha1/dataplaneservice.go b/pkg/aggregator/generated/listers/aggregation/v0alpha1/dataplaneservice.go new file mode 100644 index 00000000000..c54c7ba6fc1 --- /dev/null +++ b/pkg/aggregator/generated/listers/aggregation/v0alpha1/dataplaneservice.go @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by lister-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + v0alpha1 "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// DataPlaneServiceLister helps list DataPlaneServices. +// All objects returned here must be treated as read-only. +type DataPlaneServiceLister interface { + // List lists all DataPlaneServices in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v0alpha1.DataPlaneService, err error) + // Get retrieves the DataPlaneService from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v0alpha1.DataPlaneService, error) + DataPlaneServiceListerExpansion +} + +// dataPlaneServiceLister implements the DataPlaneServiceLister interface. +type dataPlaneServiceLister struct { + indexer cache.Indexer +} + +// NewDataPlaneServiceLister returns a new DataPlaneServiceLister. +func NewDataPlaneServiceLister(indexer cache.Indexer) DataPlaneServiceLister { + return &dataPlaneServiceLister{indexer: indexer} +} + +// List lists all DataPlaneServices in the indexer. +func (s *dataPlaneServiceLister) List(selector labels.Selector) (ret []*v0alpha1.DataPlaneService, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v0alpha1.DataPlaneService)) + }) + return ret, err +} + +// Get retrieves the DataPlaneService from the index for a given name. +func (s *dataPlaneServiceLister) Get(name string) (*v0alpha1.DataPlaneService, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v0alpha1.Resource("dataplaneservice"), name) + } + return obj.(*v0alpha1.DataPlaneService), nil +} diff --git a/pkg/aggregator/generated/listers/aggregation/v0alpha1/expansion_generated.go b/pkg/aggregator/generated/listers/aggregation/v0alpha1/expansion_generated.go new file mode 100644 index 00000000000..89d301a7819 --- /dev/null +++ b/pkg/aggregator/generated/listers/aggregation/v0alpha1/expansion_generated.go @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by lister-gen. DO NOT EDIT. + +package v0alpha1 + +// DataPlaneServiceListerExpansion allows custom methods to be added to +// DataPlaneServiceLister. +type DataPlaneServiceListerExpansion interface{} diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod new file mode 100644 index 00000000000..5512000878a --- /dev/null +++ b/pkg/aggregator/go.mod @@ -0,0 +1,157 @@ +module github.com/grafana/grafana/pkg/aggregator + +go 1.22.4 + +require ( + github.com/emicklei/go-restful/v3 v3.11.0 + github.com/grafana/grafana-plugin-sdk-go v0.241.0 + github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808213237-f4d2e064f435 + github.com/grafana/grafana/pkg/semconv v0.0.0-20240808213237-f4d2e064f435 + github.com/stretchr/testify v1.9.0 + go.opentelemetry.io/otel v1.28.0 + k8s.io/apimachinery v0.31.0 + k8s.io/apiserver v0.31.0 + k8s.io/client-go v0.31.0 + k8s.io/component-base v0.31.0 + k8s.io/klog/v2 v2.130.1 + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 +) + +require ( + github.com/BurntSushi/toml v1.3.2 // indirect + github.com/NYTimes/gziphandler v1.1.1 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/apache/arrow/go/v15 v15.0.2 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cheekybits/genny v1.0.0 // indirect + github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/getkin/kin-openapi v0.125.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/cel-go v0.20.1 // indirect + github.com/google/flatbuffers v24.3.25+incompatible // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/grafana/otel-profiling-go v0.5.1 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.7 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-plugin v1.6.1 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/yaml v0.3.1 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/magefile/mage v1.15.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattetti/filebuffer v1.0.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 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/oklog/run v1.1.0 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/smartystreets/goconvey v1.6.4 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect + github.com/unknwon/com v1.0.1 // indirect + github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect + github.com/urfave/cli v1.22.15 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/zeebo/xxh3 v1.0.2 // indirect + go.etcd.io/etcd/api/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/v3 v3.5.14 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.20.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.22.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + gonum.org/v1/gonum v0.14.0 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.31.0 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum new file mode 100644 index 00000000000..ea57e3a8534 --- /dev/null +++ b/pkg/aggregator/go.sum @@ -0,0 +1,530 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE= +github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= +github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071 h1:RdCf9hH3xq5vJifrjGB7zQlFkdRB3pAppcX2helDq2U= +github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 h1:m62nsMU279qRD9PQSWD1l66kmkXzuYcnVJqL4XLeV2M= +github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc0ytWPASlaPwQfQMQYnRf0RSDe1XvHw0Q= +github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/getkin/kin-openapi v0.125.0 h1:jyQCyf2qXS1qvs2U00xQzkGCqYPhEhZDmSmVt65fXno= +github.com/getkin/kin-openapi v0.125.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= +github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= +github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= +github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/grafana-plugin-sdk-go v0.241.0 h1:zBcSW9xV9gA9hD8UN+HjJtD7tESMZcaQhA1BI76MTxM= +github.com/grafana/grafana-plugin-sdk-go v0.241.0/go.mod h1:2HjNwzGCfaFAyR2HGoECTwAmq8vSIn2L1/1yOt4XRS4= +github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808213237-f4d2e064f435 h1:lmw60EW7JWlAEvgggktOyVkH4hF1m/+LSF/Ap0NCyi8= +github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240808213237-f4d2e064f435/go.mod h1:ORVFiW/KNRY52lNjkGwnFWCxNVfE97bJG2jr2fetq0I= +github.com/grafana/grafana/pkg/semconv v0.0.0-20240808213237-f4d2e064f435 h1:SNEeqY22DrGr5E9kGF1mKSqlOom14W9+b1u4XEGJowA= +github.com/grafana/grafana/pkg/semconv v0.0.0-20240808213237-f4d2e064f435/go.mod h1:8cz+z0i57IjN6MYmu/zZQdCg9CQcsnEHbaJBBEf3KQo= +github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= +github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= +github.com/grafana/pyroscope-go/godeltaprof v0.1.7 h1:C11j63y7gymiW8VugJ9ZW0pWfxTZugdSJyC48olk5KY= +github.com/grafana/pyroscope-go/godeltaprof v0.1.7/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 h1:uGoIog/wiQHI9GAxXO5TJbT0wWKH3O9HhOJW1F9c3fY= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI= +github.com/hashicorp/go-plugin v1.6.1/go.mod h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1hZyMK0PWAw0= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= +github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 h1:SwcnSwBR7X/5EHJQlXBockkJVIMRVt5yKaesBPMtyZQ= +github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6/go.mod h1:WrYiIuiXUMIvTDAQw97C+9l0CnBmCcvosPjN3XDqS/o= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= +github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 h1:aVGB3YnaS/JNfOW3tiHIlmNmTDg618va+eT0mVomgyI= +github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8/go.mod h1:fVle4kNr08ydeohzYafr20oZzbAkhQT39gKK/pFQ5M4= +github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= +github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= +github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3/go.mod h1:1xEUf2abjfP92w2GZTV+GgaRxXErwRXcClbUwrNJffU= +github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a h1:vcrhXnj9g9PIE+cmZgaPSwOyJ8MAQTRmsgGrB0x5rF4= +github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a/go.mod h1:1xEUf2abjfP92w2GZTV+GgaRxXErwRXcClbUwrNJffU= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM= +github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0= +go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU= +go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ= +go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI= +go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8= +go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= +go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg= +go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk= +go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= +go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= +go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= +go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= +go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= +go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0 h1:IVtyPth4Rs5P8wIf0mP2KVKFNTJ4paX9qQ4Hkh5gFdc= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.53.0/go.mod h1:ImRBLMJv177/pwiLZ7tU7HDGNdBv7rS0HQ99eN/zBl8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 h1:xQ3ktSVS128JWIaN1DiPGIjcH+GsvkibIAVRWFjS9eM= +go.opentelemetry.io/contrib/propagators/jaeger v1.28.0/go.mod h1:O9HIyI2kVBrFoEwQZ0IN6PHXykGoit4mZV2aEjkTRH4= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.20.0 h1:ja+d7Aea/9PgGxB63+E0jtRFpma717wubS0KFkZpmYw= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.20.0/go.mod h1:Yc1eg51SJy7xZdOTyg1xyFcwE+ghcWh3/0hKeLo6Wlo= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= +gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo= +gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= +k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= +k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= +k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= +k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= +k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= +k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= +k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= +k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/pkg/aggregator/registry/dataplaneservice/rest/storage.go b/pkg/aggregator/registry/dataplaneservice/rest/storage.go new file mode 100644 index 00000000000..abfc947e6fd --- /dev/null +++ b/pkg/aggregator/registry/dataplaneservice/rest/storage.go @@ -0,0 +1,33 @@ +package rest + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" + genericapiserver "k8s.io/apiserver/pkg/server" + serverstorage "k8s.io/apiserver/pkg/server/storage" + + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation" + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + aggregatorscheme "github.com/grafana/grafana/pkg/aggregator/apiserver/scheme" + dataplaneservicestorage "github.com/grafana/grafana/pkg/aggregator/registry/dataplaneservice/storage" +) + +// NewRESTStorage returns an APIGroupInfo object that will work against dataplaneservice. +func NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter, shouldServeBeta bool) genericapiserver.APIGroupInfo { + apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(aggregation.GROUP, aggregatorscheme.Scheme, metav1.ParameterCodec, aggregatorscheme.Codecs) + + storage := map[string]rest.Storage{} + + if resource := "dataplaneservices"; apiResourceConfigSource.ResourceEnabled(v0alpha1.SchemeGroupVersion.WithResource(resource)) { + dataplaneServiceREST := dataplaneservicestorage.NewREST(aggregatorscheme.Scheme, restOptionsGetter) + storage[resource] = dataplaneServiceREST + storage[resource+"/status"] = dataplaneservicestorage.NewStatusREST(aggregatorscheme.Scheme, dataplaneServiceREST) + } + + if len(storage) > 0 { + apiGroupInfo.VersionedResourcesStorageMap["v0alpha1"] = storage + } + + return apiGroupInfo +} diff --git a/pkg/aggregator/registry/dataplaneservice/storage/storage.go b/pkg/aggregator/registry/dataplaneservice/storage/storage.go new file mode 100644 index 00000000000..bb7d69de7fa --- /dev/null +++ b/pkg/aggregator/registry/dataplaneservice/storage/storage.go @@ -0,0 +1,151 @@ +package storage + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/api/meta" + metatable "k8s.io/apimachinery/pkg/api/meta/table" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" + + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation" + "github.com/grafana/grafana/pkg/aggregator/registry/dataplaneservice" +) + +// REST implements a RESTStorage for Data Plane services. +type REST struct { + *genericregistry.Store +} + +// NewREST returns a RESTStorage object that will work against Data Plane services. +func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST { + strategy := dataplaneservice.NewStrategy(scheme) + store := &genericregistry.Store{ + NewFunc: func() runtime.Object { return &aggregation.DataPlaneService{} }, + NewListFunc: func() runtime.Object { return &aggregation.DataPlaneServiceList{} }, + PredicateFunc: dataplaneservice.MatchDataPlaneService, + DefaultQualifiedResource: aggregation.Resource("dataplaneservices"), + SingularQualifiedResource: aggregation.Resource("dataplaneservice"), + + CreateStrategy: strategy, + UpdateStrategy: strategy, + DeleteStrategy: strategy, + ResetFieldsStrategy: strategy, + + TableConvertor: rest.NewDefaultTableConvertor(aggregation.Resource("dataplaneservices")), + } + options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: dataplaneservice.GetAttrs} + if err := store.CompleteWithOptions(options); err != nil { + panic(err) // TODO: Propagate error up + } + return &REST{store} +} + +// Implement CategoriesProvider +var _ rest.CategoriesProvider = &REST{} + +// Categories implements the CategoriesProvider interface. Returns a list of categories a resource is part of. +func (c *REST) Categories() []string { + return []string{"dataplane"} +} + +var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc() + +// ConvertToTable implements the TableConvertor interface for REST. +func (c *REST) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { + table := &metav1.Table{ + ColumnDefinitions: []metav1.TableColumnDefinition{ + {Name: "Name", Type: "string", Format: "name", Description: swaggerMetadataDescriptions["name"]}, + {Name: "Available", Type: "string", Description: "Whether this service is available."}, + {Name: "Age", Type: "string", Description: swaggerMetadataDescriptions["creationTimestamp"]}, + }, + } + if m, err := meta.ListAccessor(obj); err == nil { + table.ResourceVersion = m.GetResourceVersion() + table.Continue = m.GetContinue() + table.RemainingItemCount = m.GetRemainingItemCount() + } else { + if m, err := meta.CommonAccessor(obj); err == nil { + table.ResourceVersion = m.GetResourceVersion() + } + } + + var err error + table.Rows, err = metatable.MetaToTableRow(obj, func(obj runtime.Object, m metav1.Object, name, age string) ([]interface{}, error) { + svc := obj.(*aggregation.DataPlaneService) + status := string(aggregation.ConditionUnknown) + if condition := getCondition(svc.Status.Conditions, "Available"); condition != nil { + switch { + case condition.Status == aggregation.ConditionTrue: + status = string(condition.Status) + case len(condition.Reason) > 0: + status = fmt.Sprintf("%s (%s)", condition.Status, condition.Reason) + default: + status = string(condition.Status) + } + } + return []interface{}{name, status, age}, nil + }) + return table, err +} + +func getCondition(conditions []aggregation.DataPlaneServiceCondition, conditionType aggregation.DataPlaneServiceConditionType) *aggregation.DataPlaneServiceCondition { + for i, condition := range conditions { + if condition.Type == conditionType { + return &conditions[i] + } + } + return nil +} + +// NewStatusREST makes a RESTStorage for status that has more limited options. +// It is based on the original REST so that we can share the same underlying store +func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST { + strategy := dataplaneservice.NewStatusStrategy(scheme) + statusStore := *rest.Store + statusStore.CreateStrategy = nil + statusStore.DeleteStrategy = nil + statusStore.UpdateStrategy = strategy + statusStore.ResetFieldsStrategy = strategy + return &StatusREST{store: &statusStore} +} + +// StatusREST implements the REST endpoint for changing the status of an DataPlaneService. +type StatusREST struct { + store *genericregistry.Store +} + +var _ = rest.Patcher(&StatusREST{}) + +// New creates a new DataPlaneService object. +func (r *StatusREST) New() runtime.Object { + return &aggregation.DataPlaneService{} +} + +// Destroy cleans up resources on shutdown. +func (r *StatusREST) Destroy() { + // Given that underlying store is shared with REST, + // we don't destroy it here explicitly. +} + +// Get retrieves the object from the storage. It is required to support Patch. +func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return r.store.Get(ctx, name, options) +} + +// Update alters the status subset of an object. +func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { + // We are explicitly setting forceAllowCreate to false in the call to the underlying storage because + // subresources should never allow create on update. + return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options) +} + +// GetResetFields implements rest.ResetFieldsStrategy +func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return r.store.GetResetFields() +} diff --git a/pkg/aggregator/registry/dataplaneservice/strategy.go b/pkg/aggregator/registry/dataplaneservice/strategy.go new file mode 100644 index 00000000000..9671aa0a07d --- /dev/null +++ b/pkg/aggregator/registry/dataplaneservice/strategy.go @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// Provenance-includes-location: https://github.com/kubernetes/kube-aggregator/blob/master/pkg/registry/apiservice/strategy.go +// Provenance-includes-license: Apache-2.0 +// Provenance-includes-copyright: The Kubernetes Authors. + +package dataplaneservice + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage" + "k8s.io/apiserver/pkg/storage/names" + + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" +) + +type dataPlaneServiceStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +// dataPlaneServiceStrategy must implement rest.RESTCreateUpdateStrategy +var _ rest.RESTCreateUpdateStrategy = dataPlaneServiceStrategy{} +var Strategy = dataPlaneServiceStrategy{} + +// NewStrategy creates a new dataPlaneServiceStrategy. +func NewStrategy(typer runtime.ObjectTyper) rest.CreateUpdateResetFieldsStrategy { + return dataPlaneServiceStrategy{typer, names.SimpleNameGenerator} +} + +func (dataPlaneServiceStrategy) NamespaceScoped() bool { + return false +} + +func (dataPlaneServiceStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + fields := map[fieldpath.APIVersion]*fieldpath.Set{ + "aggregation.grafana.app/v0alpha1": fieldpath.NewSet( + fieldpath.MakePathOrDie("status"), + ), + } + + return fields +} + +func (dataPlaneServiceStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { +} + +func (dataPlaneServiceStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newDataPlaneService := obj.(*aggregation.DataPlaneService) + oldDataPlaneService := old.(*aggregation.DataPlaneService) + newDataPlaneService.Status = oldDataPlaneService.Status +} + +func (dataPlaneServiceStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { + return field.ErrorList{} +} + +// WarningsOnCreate returns warnings for the creation of the given object. +func (dataPlaneServiceStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { + return nil +} + +func (dataPlaneServiceStrategy) AllowCreateOnUpdate() bool { + return false +} + +func (dataPlaneServiceStrategy) AllowUnconditionalUpdate() bool { + return false +} + +func (dataPlaneServiceStrategy) Canonicalize(obj runtime.Object) { +} + +func (dataPlaneServiceStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + return field.ErrorList{} +} + +// WarningsOnUpdate returns warnings for the given update. +func (dataPlaneServiceStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { + return nil +} + +type dataPlaneServiceStatusStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +// NewStatusStrategy creates a new dataPlaneServiceStatusStrategy. +func NewStatusStrategy(typer runtime.ObjectTyper) rest.UpdateResetFieldsStrategy { + return dataPlaneServiceStatusStrategy{typer, names.SimpleNameGenerator} +} + +func (dataPlaneServiceStatusStrategy) NamespaceScoped() bool { + return false +} + +func (dataPlaneServiceStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + fields := map[fieldpath.APIVersion]*fieldpath.Set{ + "aggregation.grafana.app/v0alpha1": fieldpath.NewSet( + fieldpath.MakePathOrDie("spec"), + fieldpath.MakePathOrDie("metadata"), + ), + } + + return fields +} + +func (dataPlaneServiceStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newDataPlaneService := obj.(*aggregation.DataPlaneService) + oldDataPlaneService := old.(*aggregation.DataPlaneService) + newDataPlaneService.Spec = oldDataPlaneService.Spec + newDataPlaneService.Labels = oldDataPlaneService.Labels + newDataPlaneService.Annotations = oldDataPlaneService.Annotations + newDataPlaneService.Finalizers = oldDataPlaneService.Finalizers + newDataPlaneService.OwnerReferences = oldDataPlaneService.OwnerReferences +} + +func (dataPlaneServiceStatusStrategy) AllowCreateOnUpdate() bool { + return false +} + +func (dataPlaneServiceStatusStrategy) AllowUnconditionalUpdate() bool { + return false +} + +// Canonicalize normalizes the object after validation. +func (dataPlaneServiceStatusStrategy) Canonicalize(obj runtime.Object) { +} + +// ValidateUpdate validates an update of dataPlaneServiceStatusStrategy. +func (dataPlaneServiceStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + return field.ErrorList{} +} + +// WarningsOnUpdate returns warnings for the given update. +func (dataPlaneServiceStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { + return nil +} + +// GetAttrs returns the labels and fields of an API server for filtering purposes. +func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { + s, ok := obj.(*aggregation.DataPlaneService) + if !ok { + return nil, nil, fmt.Errorf("given object is not a DataPlaneService") + } + return labels.Set(s.ObjectMeta.Labels), ToSelectableFields(s), nil +} + +// MatchDataPlaneService is the filter used by the generic etcd backend to watch events +// from etcd to clients of the apiserver only interested in specific labels/fields. +func MatchDataPlaneService(label labels.Selector, field fields.Selector) storage.SelectionPredicate { + return storage.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: GetAttrs, + } +} + +// ToSelectableFields returns a field set that represents the object. +func ToSelectableFields(obj *aggregation.DataPlaneService) fields.Set { + return generic.ObjectMetaFieldsSet(&obj.ObjectMeta, true) +} diff --git a/pkg/services/apiserver/aggregator/aggregator.go b/pkg/services/apiserver/aggregator/aggregator.go index b3066f88e5a..44078245990 100644 --- a/pkg/services/apiserver/aggregator/aggregator.go +++ b/pkg/services/apiserver/aggregator/aggregator.go @@ -124,8 +124,8 @@ func CreateAggregatorConfig(commandOptions *options.Options, sharedConfig generi ClientConfig: sharedConfig.LoopbackClientConfig, }, ExtraConfig: aggregatorapiserver.ExtraConfig{ - ProxyClientCertFile: commandOptions.AggregatorOptions.ProxyClientCertFile, - ProxyClientKeyFile: commandOptions.AggregatorOptions.ProxyClientKeyFile, + ProxyClientCertFile: commandOptions.KubeAggregatorOptions.ProxyClientCertFile, + ProxyClientKeyFile: commandOptions.KubeAggregatorOptions.ProxyClientKeyFile, // NOTE: while ProxyTransport can be skipped in the configuration, it allows honoring // DISABLE_HTTP2, HTTPS_PROXY and NO_PROXY env vars as needed ProxyTransport: createProxyTransport(), @@ -133,7 +133,7 @@ func CreateAggregatorConfig(commandOptions *options.Options, sharedConfig generi }, } - if err := commandOptions.AggregatorOptions.ApplyTo(aggregatorConfig, commandOptions.RecommendedOptions.Etcd); err != nil { + if err := commandOptions.KubeAggregatorOptions.ApplyTo(aggregatorConfig, commandOptions.RecommendedOptions.Etcd); err != nil { return nil, err } @@ -144,15 +144,15 @@ func CreateAggregatorConfig(commandOptions *options.Options, sharedConfig generi APIVersionPriorities[serviceAPIBuilder.GetGroupVersion()] = Priority{Group: 15000, Version: int32(1)} // Exit early, if no remote services file is configured - if commandOptions.AggregatorOptions.RemoteServicesFile == "" { + if commandOptions.KubeAggregatorOptions.RemoteServicesFile == "" { return NewConfig(aggregatorConfig, sharedInformerFactory, []builder.APIGroupBuilder{serviceAPIBuilder}, nil), nil } - _, err = readCABundlePEM(commandOptions.AggregatorOptions.APIServiceCABundleFile, commandOptions.ExtraOptions.DevMode) + _, err = readCABundlePEM(commandOptions.KubeAggregatorOptions.APIServiceCABundleFile, commandOptions.ExtraOptions.DevMode) if err != nil { return nil, err } - remoteServices, err := readRemoteServices(commandOptions.AggregatorOptions.RemoteServicesFile) + remoteServices, err := readRemoteServices(commandOptions.KubeAggregatorOptions.RemoteServicesFile) if err != nil { return nil, err } diff --git a/pkg/services/apiserver/config.go b/pkg/services/apiserver/config.go index dee64ca4848..b6172e2fe0a 100644 --- a/pkg/services/apiserver/config.go +++ b/pkg/services/apiserver/config.go @@ -43,11 +43,11 @@ func applyGrafanaConfig(cfg *setting.Cfg, features featuremgmt.FeatureToggles, o o.RecommendedOptions.Authentication.RemoteKubeConfigFileOptional = true o.RecommendedOptions.Authorization.RemoteKubeConfigFileOptional = true - o.AggregatorOptions.ProxyClientCertFile = apiserverCfg.Key("proxy_client_cert_file").MustString("") - o.AggregatorOptions.ProxyClientKeyFile = apiserverCfg.Key("proxy_client_key_file").MustString("") + o.KubeAggregatorOptions.ProxyClientCertFile = apiserverCfg.Key("proxy_client_cert_file").MustString("") + o.KubeAggregatorOptions.ProxyClientKeyFile = apiserverCfg.Key("proxy_client_key_file").MustString("") - o.AggregatorOptions.APIServiceCABundleFile = apiserverCfg.Key("apiservice_ca_bundle_file").MustString("") - o.AggregatorOptions.RemoteServicesFile = apiserverCfg.Key("remote_services_file").MustString("") + o.KubeAggregatorOptions.APIServiceCABundleFile = apiserverCfg.Key("apiservice_ca_bundle_file").MustString("") + o.KubeAggregatorOptions.RemoteServicesFile = apiserverCfg.Key("remote_services_file").MustString("") o.RecommendedOptions.Admission = nil o.RecommendedOptions.CoreAPI = nil diff --git a/pkg/services/apiserver/options/grafana-aggregator.go b/pkg/services/apiserver/options/grafana-aggregator.go new file mode 100644 index 00000000000..693f27ddd34 --- /dev/null +++ b/pkg/services/apiserver/options/grafana-aggregator.go @@ -0,0 +1,94 @@ +package options + +import ( + "maps" + + "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/endpoints/openapi" + genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/options" + "k8s.io/apiserver/pkg/server/resourceconfig" + "k8s.io/kube-openapi/pkg/common" + + "github.com/grafana/grafana/pkg/aggregator/apis/aggregation/v0alpha1" + aggregatorapiserver "github.com/grafana/grafana/pkg/aggregator/apiserver" + aggregatorscheme "github.com/grafana/grafana/pkg/aggregator/apiserver/scheme" + commonv0alpha1 "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + "github.com/grafana/grafana/pkg/storage/unified/apistore" +) + +// GrafanaAggregatorOptions contains the state for the aggregator apiserver +type GrafanaAggregatorOptions struct { +} + +func NewGrafanaAggregatorOptions() *GrafanaAggregatorOptions { + return &GrafanaAggregatorOptions{} +} + +func (o *GrafanaAggregatorOptions) AddFlags(fs *pflag.FlagSet) { + if o == nil { + return + } + // TODO: do we need any CLI flags here? +} + +func (o *GrafanaAggregatorOptions) Validate() []error { + if o == nil { + return nil + } + + // TODO: do we need to validate anything here? + return nil +} + +func (o *GrafanaAggregatorOptions) ApplyTo(aggregatorConfig *aggregatorapiserver.Config, etcdOpts *options.EtcdOptions) error { + genericConfig := aggregatorConfig.GenericConfig + + genericConfig.PostStartHooks = map[string]genericapiserver.PostStartHookConfigEntry{} + genericConfig.RESTOptionsGetter = nil + + getOpenAPIDefinitions := func(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { + defs := commonv0alpha1.GetOpenAPIDefinitions(ref) + maps.Copy(defs, v0alpha1.GetOpenAPIDefinitions(ref)) + return defs + } + + genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(getOpenAPIDefinitions, openapi.NewDefinitionNamer(aggregatorscheme.Scheme)) + genericConfig.OpenAPIConfig.Info.Title = "Grafana Aggregator" + genericConfig.OpenAPIConfig.Info.Version = "0.1" + + genericConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(getOpenAPIDefinitions, openapi.NewDefinitionNamer(aggregatorscheme.Scheme)) + genericConfig.OpenAPIV3Config.Info.Title = "Grafana Aggregator" + genericConfig.OpenAPIV3Config.Info.Version = "0.1" + + // copy the etcd options so we don't mutate originals. + // we assume that the etcd options have been completed already. avoid messing with anything outside + // of changes to StorageConfig as that may lead to unexpected behavior when the options are applied. + etcdOptions := *etcdOpts + etcdOptions.StorageConfig.Codec = aggregatorscheme.Codecs.LegacyCodec(v0alpha1.SchemeGroupVersion) + etcdOptions.StorageConfig.EncodeVersioner = runtime.NewMultiGroupVersioner(v0alpha1.SchemeGroupVersion, schema.GroupKind{Group: v0alpha1.SchemeGroupVersion.Group}) + etcdOptions.SkipHealthEndpoints = true // avoid double wiring of health checks + if err := etcdOptions.ApplyTo(&genericConfig.Config); err != nil { + return err + } + // override the RESTOptionsGetter to use the in memory storage options + restOptionsGetter, err := apistore.NewRESTOptionsGetterMemory(etcdOptions.StorageConfig) + if err != nil { + return err + } + aggregatorConfig.GenericConfig.RESTOptionsGetter = restOptionsGetter + + // prevent generic API server from installing the OpenAPI handler. Aggregator server has its own customized OpenAPI handler. + genericConfig.SkipOpenAPIInstallation = true + mergedResourceConfig, err := resourceconfig.MergeAPIResourceConfigs(aggregatorapiserver.DefaultAPIResourceConfigSource(), nil, aggregatorscheme.Scheme) + if err != nil { + return err + } + genericConfig.MergedResourceConfig = mergedResourceConfig + + genericConfig.PostStartHooks = map[string]genericapiserver.PostStartHookConfigEntry{} + + return nil +} diff --git a/pkg/services/apiserver/options/aggregator.go b/pkg/services/apiserver/options/kube-aggregator.go similarity index 90% rename from pkg/services/apiserver/options/aggregator.go rename to pkg/services/apiserver/options/kube-aggregator.go index 4b51502820a..1186747f379 100644 --- a/pkg/services/apiserver/options/aggregator.go +++ b/pkg/services/apiserver/options/kube-aggregator.go @@ -18,8 +18,8 @@ import ( "github.com/grafana/grafana/pkg/storage/unified/apistore" ) -// AggregatorServerOptions contains the state for the aggregator apiserver -type AggregatorServerOptions struct { +// KubeAggregatorOptions contains the state for the aggregator apiserver +type KubeAggregatorOptions struct { AlternateDNS []string ProxyClientCertFile string ProxyClientKeyFile string @@ -27,11 +27,11 @@ type AggregatorServerOptions struct { APIServiceCABundleFile string } -func NewAggregatorServerOptions() *AggregatorServerOptions { - return &AggregatorServerOptions{} +func NewAggregatorServerOptions() *KubeAggregatorOptions { + return &KubeAggregatorOptions{} } -func (o *AggregatorServerOptions) AddFlags(fs *pflag.FlagSet) { +func (o *KubeAggregatorOptions) AddFlags(fs *pflag.FlagSet) { if o == nil { return } @@ -43,7 +43,7 @@ func (o *AggregatorServerOptions) AddFlags(fs *pflag.FlagSet) { "path to proxy client key file") } -func (o *AggregatorServerOptions) Validate() []error { +func (o *KubeAggregatorOptions) Validate() []error { if o == nil { return nil } @@ -52,7 +52,7 @@ func (o *AggregatorServerOptions) Validate() []error { return nil } -func (o *AggregatorServerOptions) ApplyTo(aggregatorConfig *aggregatorapiserver.Config, etcdOpts *options.EtcdOptions) error { +func (o *KubeAggregatorOptions) ApplyTo(aggregatorConfig *aggregatorapiserver.Config, etcdOpts *options.EtcdOptions) error { genericConfig := aggregatorConfig.GenericConfig genericConfig.PostStartHooks = map[string]genericapiserver.PostStartHookConfigEntry{} diff --git a/pkg/services/apiserver/options/options.go b/pkg/services/apiserver/options/options.go index 56dc89a4631..7fd29359e6f 100644 --- a/pkg/services/apiserver/options/options.go +++ b/pkg/services/apiserver/options/options.go @@ -19,25 +19,28 @@ type OptionsProvider interface { const defaultEtcdPathPrefix = "/registry/grafana.app" type Options struct { - RecommendedOptions *genericoptions.RecommendedOptions - AggregatorOptions *AggregatorServerOptions - StorageOptions *StorageOptions - ExtraOptions *ExtraOptions - APIOptions []OptionsProvider + RecommendedOptions *genericoptions.RecommendedOptions + GrafanaAggregatorOptions *GrafanaAggregatorOptions + KubeAggregatorOptions *KubeAggregatorOptions + StorageOptions *StorageOptions + ExtraOptions *ExtraOptions + APIOptions []OptionsProvider } func NewOptions(codec runtime.Codec) *Options { return &Options{ - RecommendedOptions: NewRecommendedOptions(codec), - AggregatorOptions: NewAggregatorServerOptions(), - StorageOptions: NewStorageOptions(), - ExtraOptions: NewExtraOptions(), + RecommendedOptions: NewRecommendedOptions(codec), + GrafanaAggregatorOptions: NewGrafanaAggregatorOptions(), + KubeAggregatorOptions: NewAggregatorServerOptions(), + StorageOptions: NewStorageOptions(), + ExtraOptions: NewExtraOptions(), } } func (o *Options) AddFlags(fs *pflag.FlagSet) { o.RecommendedOptions.AddFlags(fs) - o.AggregatorOptions.AddFlags(fs) + o.GrafanaAggregatorOptions.AddFlags(fs) + o.KubeAggregatorOptions.AddFlags(fs) o.StorageOptions.AddFlags(fs) o.ExtraOptions.AddFlags(fs) @@ -55,7 +58,11 @@ func (o *Options) Validate() []error { return errs } - if errs := o.AggregatorOptions.Validate(); len(errs) != 0 { + if errs := o.GrafanaAggregatorOptions.Validate(); len(errs) != 0 { + return errs + } + + if errs := o.KubeAggregatorOptions.Validate(); len(errs) != 0 { return errs } diff --git a/pkg/services/apiserver/service.go b/pkg/services/apiserver/service.go index d266305fccc..4c86b38e074 100644 --- a/pkg/services/apiserver/service.go +++ b/pkg/services/apiserver/service.go @@ -7,6 +7,7 @@ import ( "path" "github.com/grafana/dskit/services" + "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" @@ -19,7 +20,9 @@ import ( genericapiserver "k8s.io/apiserver/pkg/server" clientrest "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver" + dataplaneaggregator "github.com/grafana/grafana/pkg/aggregator/apiserver" "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/apimachinery/identity" grafanaresponsewriter "github.com/grafana/grafana/pkg/apiserver/endpoints/responsewriter" @@ -30,8 +33,10 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/modules" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/registry" - "github.com/grafana/grafana/pkg/services/apiserver/aggregator" + "github.com/grafana/grafana/pkg/registry/apis/datasource" + kubeaggregator "github.com/grafana/grafana/pkg/services/apiserver/aggregator" "github.com/grafana/grafana/pkg/services/apiserver/auth/authenticator" "github.com/grafana/grafana/pkg/services/apiserver/auth/authorizer" "github.com/grafana/grafana/pkg/services/apiserver/builder" @@ -41,6 +46,7 @@ import ( contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/unified/apistore" "github.com/grafana/grafana/pkg/storage/unified/resource" @@ -117,6 +123,11 @@ type service struct { authorizer *authorizer.GrafanaAuthorizer serverLockService builder.ServerLockService kvStore kvstore.KVStore + + pluginClient plugins.Client + datasources datasource.ScopedPluginDatasourceProvider + contextProvider datasource.PluginContextWrapper + pluginStore pluginstore.Store } func ProvideService( @@ -128,19 +139,27 @@ func ProvideService( serverLockService *serverlock.ServerLockService, db db.DB, kvStore kvstore.KVStore, + pluginClient plugins.Client, + datasources datasource.ScopedPluginDatasourceProvider, + contextProvider datasource.PluginContextWrapper, + pluginStore pluginstore.Store, ) (*service, error) { s := &service{ - cfg: cfg, - features: features, - rr: rr, - startedCh: make(chan struct{}), - stopCh: make(chan struct{}), - builders: []builder.APIGroupBuilder{}, - authorizer: authorizer.NewGrafanaAuthorizer(cfg, orgService), - tracing: tracing, - db: db, // For Unified storage - metrics: metrics.ProvideRegisterer(), - kvStore: kvStore, + cfg: cfg, + features: features, + rr: rr, + startedCh: make(chan struct{}), + stopCh: make(chan struct{}), + builders: []builder.APIGroupBuilder{}, + authorizer: authorizer.NewGrafanaAuthorizer(cfg, orgService), + tracing: tracing, + db: db, // For Unified storage + metrics: metrics.ProvideRegisterer(), + kvStore: kvStore, + pluginClient: pluginClient, + datasources: datasources, + contextProvider: contextProvider, + pluginStore: pluginStore, } // This will be used when running as a dskit service @@ -214,7 +233,7 @@ func (s *service) start(ctx context.Context) error { groupVersions := make([]schema.GroupVersion, 0, len(builders)) // Install schemas - initialSize := len(aggregator.APIVersionPriorities) + initialSize := len(kubeaggregator.APIVersionPriorities) for i, b := range builders { groupVersions = append(groupVersions, b.GetGroupVersion()) if err := b.InstallSchema(Scheme); err != nil { @@ -223,7 +242,7 @@ func (s *service) start(ctx context.Context) error { if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAggregator) { // set the priority for the group+version - aggregator.APIVersionPriorities[b.GetGroupVersion()] = aggregator.Priority{Group: 15000, Version: int32(i + initialSize)} + kubeaggregator.APIVersionPriorities[b.GetGroupVersion()] = kubeaggregator.Priority{Group: 15000, Version: int32(i + initialSize)} } auth := b.GetAuthorizer() @@ -339,9 +358,24 @@ func (s *service) start(ctx context.Context) error { // stash the options for later use s.options = o - var runningServer *genericapiserver.GenericAPIServer + delegate := server + var aggregatorServer *aggregatorapiserver.APIAggregator if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAggregator) { - runningServer, err = s.startAggregator(ctx, transport, serverConfig, server, s.metrics) + aggregatorServer, err = s.createKubeAggregator(serverConfig, server, s.metrics) + if err != nil { + return err + } + delegate = aggregatorServer.GenericAPIServer + } + + var runningServer *genericapiserver.GenericAPIServer + if s.features.IsEnabledGlobally(featuremgmt.FlagDataplaneAggregator) { + runningServer, err = s.startDataplaneAggregator(ctx, transport, serverConfig, delegate) + if err != nil { + return err + } + } else if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAggregator) { + runningServer, err = s.startKubeAggregator(ctx, transport, aggregatorServer) if err != nil { return err } @@ -387,25 +421,74 @@ func (s *service) startCoreServer( return server, nil } -func (s *service) startAggregator( +func (s *service) startDataplaneAggregator( ctx context.Context, transport *roundTripperFunc, + serverConfig *genericapiserver.RecommendedConfig, + delegate *genericapiserver.GenericAPIServer, +) (*genericapiserver.GenericAPIServer, error) { + config := &dataplaneaggregator.Config{ + GenericConfig: serverConfig, + ExtraConfig: dataplaneaggregator.ExtraConfig{ + PluginClient: s.pluginClient, + PluginContextProvider: &pluginContextProvider{ + pluginStore: s.pluginStore, + datasources: s.datasources, + contextProvider: s.contextProvider, + }, + }, + } + + if err := s.options.GrafanaAggregatorOptions.ApplyTo(config, s.options.RecommendedOptions.Etcd); err != nil { + return nil, err + } + + completedConfig := config.Complete() + + aggregatorServer, err := completedConfig.NewWithDelegate(delegate) + if err != nil { + return nil, err + } + + // setup the loopback transport for the aggregator server and signal that it's ready + // ignore the lint error because the response is passed directly to the client, + // so the client will be responsible for closing the response body. + // nolint:bodyclose + transport.fn = grafanaresponsewriter.WrapHandler(aggregatorServer.GenericAPIServer.Handler) + close(transport.ready) + + prepared, err := aggregatorServer.PrepareRun() + if err != nil { + return nil, err + } + + go func() { + s.stoppedCh <- prepared.RunWithContext(ctx) + }() + + return aggregatorServer.GenericAPIServer, nil +} + +func (s *service) createKubeAggregator( serverConfig *genericapiserver.RecommendedConfig, server *genericapiserver.GenericAPIServer, reg prometheus.Registerer, -) (*genericapiserver.GenericAPIServer, error) { +) (*aggregatorapiserver.APIAggregator, error) { namespaceMapper := request.GetNamespaceMapper(s.cfg) - aggregatorConfig, err := aggregator.CreateAggregatorConfig(s.options, *serverConfig, namespaceMapper(1)) + aggregatorConfig, err := kubeaggregator.CreateAggregatorConfig(s.options, *serverConfig, namespaceMapper(1)) if err != nil { return nil, err } - aggregatorServer, err := aggregator.CreateAggregatorServer(aggregatorConfig, server, reg) - if err != nil { - return nil, err - } + return kubeaggregator.CreateAggregatorServer(aggregatorConfig, server, reg) +} +func (s *service) startKubeAggregator( + ctx context.Context, + transport *roundTripperFunc, + aggregatorServer *aggregatorapiserver.APIAggregator, +) (*genericapiserver.GenericAPIServer, error) { // setup the loopback transport for the aggregator server and signal that it's ready // ignore the lint error because the response is passed directly to the client, // so the client will be responsible for closing the response body. @@ -473,3 +556,30 @@ func (f *roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) } return f.fn(req) } + +type pluginContextProvider struct { + pluginStore pluginstore.Store + datasources datasource.ScopedPluginDatasourceProvider + contextProvider datasource.PluginContextWrapper +} + +func (p *pluginContextProvider) GetPluginContext(ctx context.Context, pluginID string, uid string) (backend.PluginContext, error) { + all := p.pluginStore.Plugins(ctx) + + var datasourceProvider datasource.PluginDatasourceProvider + for _, plugin := range all { + if plugin.ID == pluginID { + datasourceProvider = p.datasources.GetDatasourceProvider(plugin.JSONData) + } + } + if datasourceProvider == nil { + return backend.PluginContext{}, fmt.Errorf("plugin not found") + } + + s, err := datasourceProvider.GetInstanceSettings(ctx, uid) + if err != nil { + return backend.PluginContext{}, err + } + + return p.contextProvider.PluginContextForDataSource(ctx, s) +}