mirror of https://github.com/grafana/grafana.git
				
				
				
			Unistore: Avoid circular dependency when injecting restcfgprovider into FolderSvc (#99295)
* Avoid circular dependency when getting a restCfgProvider for Folder Svc Signed-off-by: Maicon Costa <maiconscosta@gmail.com> --------- Signed-off-by: Maicon Costa <maiconscosta@gmail.com>
This commit is contained in:
		
							parent
							
								
									1c858caec3
								
							
						
					
					
						commit
						45e2f95a41
					
				|  | @ -71,6 +71,10 @@ var ( | |||
| 		&metav1.PartialObjectMetadata{}, | ||||
| 		&metav1.PartialObjectMetadataList{}, | ||||
| 	} | ||||
| 
 | ||||
| 	// internal provider of the package level client Config
 | ||||
| 	restConfig RestConfigProvider | ||||
| 	ready      = make(chan struct{}) | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
|  | @ -79,6 +83,17 @@ func init() { | |||
| 	Scheme.AddUnversionedTypes(unversionedVersion, unversionedTypes...) | ||||
| } | ||||
| 
 | ||||
| // GetRestConfig return a client Config mounted at package level
 | ||||
| // This resolves circular dependency issues between apiserver, authz,
 | ||||
| // and Folder Service.
 | ||||
| // The client Config gets initialized during the first call to
 | ||||
| // ProvideService.
 | ||||
| // Any call to GetRestConfig will block until we have a restConfig available
 | ||||
| func GetRestConfig(ctx context.Context) *clientrest.Config { | ||||
| 	<-ready | ||||
| 	return restConfig.GetRestConfig(ctx) | ||||
| } | ||||
| 
 | ||||
| type Service interface { | ||||
| 	services.NamedService | ||||
| 	registry.BackgroundService | ||||
|  | @ -210,6 +225,12 @@ func ProvideService( | |||
| 	s.rr.Group("/openapi", proxyHandler) | ||||
| 	s.rr.Group("/version", proxyHandler) | ||||
| 
 | ||||
| 	// only set the package level restConfig once
 | ||||
| 	if restConfig == nil { | ||||
| 		restConfig = s | ||||
| 		close(ready) | ||||
| 	} | ||||
| 
 | ||||
| 	return s, nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/infra/metrics" | ||||
| 	"github.com/grafana/grafana/pkg/infra/tracing" | ||||
| 	"github.com/grafana/grafana/pkg/services/accesscontrol" | ||||
| 	"github.com/grafana/grafana/pkg/services/apiserver" | ||||
| 	"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" | ||||
| 	"github.com/grafana/grafana/pkg/services/dashboards" | ||||
| 	"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess" | ||||
|  | @ -79,9 +80,10 @@ func ProvideService( | |||
| 		gvr:                v0alpha1.FolderResourceInfo.GroupVersionResource(), | ||||
| 		namespacer:         request.GetNamespaceMapper(cfg), | ||||
| 		cfg:                cfg, | ||||
| 		restConfigProvider: apiserver.GetRestConfig, | ||||
| 	} | ||||
| 
 | ||||
| 	unifiedStore := ProvideUnifiedStore(cfg) | ||||
| 	unifiedStore := ProvideUnifiedStore(k8sHandler) | ||||
| 
 | ||||
| 	srv := &Service{ | ||||
| 		log:                  slog.Default().With("logger", "folder-service"), | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ import ( | |||
| 	"golang.org/x/exp/slices" | ||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||
| 	"k8s.io/client-go/dynamic" | ||||
| 	"k8s.io/client-go/rest" | ||||
| 	clientrest "k8s.io/client-go/rest" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/apimachinery/identity" | ||||
| 	"github.com/grafana/grafana/pkg/events" | ||||
|  | @ -39,6 +39,7 @@ type foldk8sHandler struct { | |||
| 	cfg                *setting.Cfg | ||||
| 	namespacer         request.NamespaceMapper | ||||
| 	gvr                schema.GroupVersionResource | ||||
| 	restConfigProvider func(ctx context.Context) *clientrest.Config | ||||
| } | ||||
| 
 | ||||
| func (s *Service) getFoldersFromApiServer(ctx context.Context, q folder.GetFoldersQuery) ([]*folder.Folder, error) { | ||||
|  | @ -680,20 +681,16 @@ func (s *Service) getDescendantCountsFromApiServer(ctx context.Context, q *folde | |||
| // -----------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| func (fk8s *foldk8sHandler) getClient(ctx context.Context, orgID int64) (dynamic.ResourceInterface, bool) { | ||||
| 	cfg := &rest.Config{ | ||||
| 		Host:    fk8s.cfg.AppURL, | ||||
| 		APIPath: "/apis", | ||||
| 		TLSClientConfig: rest.TLSClientConfig{ | ||||
| 			Insecure: true, // Skip TLS verification
 | ||||
| 		}, | ||||
| 		Username: fk8s.cfg.AdminUser, | ||||
| 		Password: fk8s.cfg.AdminPassword, | ||||
| 	cfg := fk8s.restConfigProvider(ctx) | ||||
| 	if cfg == nil { | ||||
| 		return nil, false | ||||
| 	} | ||||
| 
 | ||||
| 	dyn, err := dynamic.NewForConfig(cfg) | ||||
| 	if err != nil { | ||||
| 		return nil, false | ||||
| 	} | ||||
| 
 | ||||
| 	return dyn.Resource(fk8s.gvr).Namespace(fk8s.getNamespace(orgID)), true | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ import ( | |||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	clientrest "k8s.io/client-go/rest" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/apimachinery/identity" | ||||
| 	"github.com/grafana/grafana/pkg/apis/folder/v0alpha1" | ||||
|  | @ -22,6 +23,7 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/services/accesscontrol" | ||||
| 	"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" | ||||
| 	"github.com/grafana/grafana/pkg/services/accesscontrol/actest" | ||||
| 	"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" | ||||
| 	"github.com/grafana/grafana/pkg/services/dashboards" | ||||
| 	"github.com/grafana/grafana/pkg/services/featuremgmt" | ||||
| 	"github.com/grafana/grafana/pkg/services/folder" | ||||
|  | @ -31,6 +33,16 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/services/user" | ||||
| ) | ||||
| 
 | ||||
| type rcp struct { | ||||
| 	Host string | ||||
| } | ||||
| 
 | ||||
| func (r rcp) GetRestConfig(ctx context.Context) *clientrest.Config { | ||||
| 	return &clientrest.Config{ | ||||
| 		Host: r.Host, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { | ||||
| 	if testing.Short() { | ||||
| 		t.Skip("skipping integration test") | ||||
|  | @ -147,7 +159,18 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { | |||
| 	db, cfg := sqlstore.InitTestDB(t) | ||||
| 	cfg.AppURL = folderApiServerMock.URL | ||||
| 
 | ||||
| 	unifiedStore := ProvideUnifiedStore(cfg) | ||||
| 	restCfgProvider := rcp{ | ||||
| 		Host: folderApiServerMock.URL, | ||||
| 	} | ||||
| 
 | ||||
| 	k8sHandler := &foldk8sHandler{ | ||||
| 		gvr:                v0alpha1.FolderResourceInfo.GroupVersionResource(), | ||||
| 		namespacer:         request.GetNamespaceMapper(cfg), | ||||
| 		cfg:                cfg, | ||||
| 		restConfigProvider: restCfgProvider.GetRestConfig, | ||||
| 	} | ||||
| 
 | ||||
| 	unifiedStore := ProvideUnifiedStore(k8sHandler) | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	usr := &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{ | ||||
|  |  | |||
|  | @ -15,9 +15,7 @@ import ( | |||
| 	"github.com/grafana/grafana/pkg/apis/folder/v0alpha1" | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
| 	internalfolders "github.com/grafana/grafana/pkg/registry/apis/folders" | ||||
| 	"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" | ||||
| 	"github.com/grafana/grafana/pkg/services/folder" | ||||
| 	"github.com/grafana/grafana/pkg/setting" | ||||
| 	"github.com/grafana/grafana/pkg/util" | ||||
| ) | ||||
| 
 | ||||
|  | @ -29,13 +27,7 @@ type FolderUnifiedStoreImpl struct { | |||
| // sqlStore implements the store interface.
 | ||||
| var _ folder.Store = (*FolderUnifiedStoreImpl)(nil) | ||||
| 
 | ||||
| func ProvideUnifiedStore(cfg *setting.Cfg) *FolderUnifiedStoreImpl { | ||||
| 	k8sHandler := &foldk8sHandler{ | ||||
| 		gvr:        v0alpha1.FolderResourceInfo.GroupVersionResource(), | ||||
| 		namespacer: request.GetNamespaceMapper(cfg), | ||||
| 		cfg:        cfg, | ||||
| 	} | ||||
| 
 | ||||
| func ProvideUnifiedStore(k8sHandler *foldk8sHandler) *FolderUnifiedStoreImpl { | ||||
| 	return &FolderUnifiedStoreImpl{ | ||||
| 		k8sclient: k8sHandler, | ||||
| 		log:       log.New("folder-store"), | ||||
|  |  | |||
|  | @ -292,6 +292,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc | |||
| github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= | ||||
| github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o= | ||||
| github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= | ||||
| github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= | ||||
| github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= | ||||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | ||||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | ||||
| github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc= | ||||
|  | @ -567,12 +569,16 @@ github.com/grafana/grafana-plugin-sdk-go v0.262.0 h1:R2DV6lwBQE5zaogxX3PorD9Seo8 | |||
| github.com/grafana/grafana-plugin-sdk-go v0.262.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw= | ||||
| github.com/grafana/grafana/pkg/aggregator v0.0.0-20250121113133-e747350fee2d h1:aBD5kzsIAh50vjNqUkWK9mNpLGIBYAnKkWtUepGNAiQ= | ||||
| github.com/grafana/grafana/pkg/aggregator v0.0.0-20250121113133-e747350fee2d/go.mod h1:1sq0guad+G4SUTlBgx7SXfhnzy7D86K/LcVOtiQCiMA= | ||||
| github.com/grafana/grafana/pkg/promlib v0.0.7 h1:BdpanKOKnID/l1BJZLhE7TRNtmq7aOVdou1LBFWaMmU= | ||||
| github.com/grafana/grafana/pkg/promlib v0.0.7/go.mod h1:rnwJXCA2xRwb7F27NB35iO/JsLL/H/+eVXECk/hrEhQ= | ||||
| github.com/grafana/grafana/pkg/semconv v0.0.0-20250121113133-e747350fee2d h1:cYBjuhb3m5oC6Z00Kw8DdySFaNhwb38SMxx0oXnz5vQ= | ||||
| github.com/grafana/grafana/pkg/semconv v0.0.0-20250121113133-e747350fee2d/go.mod h1:tfLnBpPYgwrBMRz4EXqPCZJyCjEG4Ev37FSlXnocJ2c= | ||||
| 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.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg= | ||||
| github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= | ||||
| github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= | ||||
| github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= | ||||
| github.com/grafana/sqlds/v4 v4.1.3 h1:+Hy5Yz+tSbD5N3yuLM0VKTsWlVaCzM1S1m1QEBZL7fE= | ||||
| github.com/grafana/sqlds/v4 v4.1.3/go.mod h1:Lx8IR939lIrCBpCKthv7AXs7E7bmNWPgt0gene/idT8= | ||||
| github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= | ||||
|  | @ -912,6 +918,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O | |||
| github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= | ||||
| 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/prometheus/prometheus v0.301.0 h1:0z8dgegmILivNomCd79RKvVkIols8vBGPKmcIBc7OyY= | ||||
| github.com/prometheus/prometheus v0.301.0/go.mod h1:BJLjWCKNfRfjp7Q48DrAjARnCi7GhfUVvUFEAWTssZM= | ||||
| github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | ||||
| github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= | ||||
| github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue