Skip to content

Commit

Permalink
Unistore: Avoid circular dependency when injecting restcfgprovider in…
Browse files Browse the repository at this point in the history
…to FolderSvc (grafana#99295)

* Avoid circular dependency when getting a restCfgProvider for Folder Svc

Signed-off-by: Maicon Costa <[email protected]>

---------

Signed-off-by: Maicon Costa <[email protected]>
  • Loading branch information
filewalkwithme authored Jan 21, 2025
1 parent 1c858ca commit 45e2f95
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 26 deletions.
21 changes: 21 additions & 0 deletions pkg/services/apiserver/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
10 changes: 6 additions & 4 deletions pkg/services/folder/folderimpl/folder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -76,12 +77,13 @@ func ProvideService(
tracer tracing.Tracer,
) *Service {
k8sHandler := &foldk8sHandler{
gvr: v0alpha1.FolderResourceInfo.GroupVersionResource(),
namespacer: request.GetNamespaceMapper(cfg),
cfg: cfg,
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"),
Expand Down
21 changes: 9 additions & 12 deletions pkg/services/folder/folderimpl/folder_unifiedstorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -36,9 +36,10 @@ type folderK8sHandler interface {
var _ folderK8sHandler = (*foldk8sHandler)(nil)

type foldk8sHandler struct {
cfg *setting.Cfg
namespacer request.NamespaceMapper
gvr schema.GroupVersionResource
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) {
Expand Down Expand Up @@ -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
}

Expand Down
25 changes: 24 additions & 1 deletion pkg/services/folder/folderimpl/folder_unifiedstorage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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")
Expand Down Expand Up @@ -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{
Expand Down
10 changes: 1 addition & 9 deletions pkg/services/folder/folderimpl/unifiedstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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"),
Expand Down
8 changes: 8 additions & 0 deletions pkg/storage/unified/apistore/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down

0 comments on commit 45e2f95

Please sign in to comment.