Provisioning: Build and use repository factory in repository controller (#110585)
Build and use repository factory
This commit is contained in:
@@ -16,24 +16,28 @@ import (
|
||||
typedclient "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1"
|
||||
informerv0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/generated/informers/externalversions/provisioning/v0alpha1"
|
||||
listers "github.com/grafana/grafana/apps/provisioning/pkg/generated/listers/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
||||
)
|
||||
|
||||
type RepositoryController struct {
|
||||
client typedclient.ProvisioningV0alpha1Interface
|
||||
repoLister listers.RepositoryLister
|
||||
repoSynced cache.InformerSynced
|
||||
logger logging.Logger
|
||||
queue workqueue.TypedRateLimitingInterface[string]
|
||||
client typedclient.ProvisioningV0alpha1Interface
|
||||
repoLister listers.RepositoryLister
|
||||
repoSynced cache.InformerSynced
|
||||
logger logging.Logger
|
||||
queue workqueue.TypedRateLimitingInterface[string]
|
||||
repoFactory repository.Factory
|
||||
}
|
||||
|
||||
func NewRepositoryController(
|
||||
provisioningClient typedclient.ProvisioningV0alpha1Interface,
|
||||
repoInformer informerv0alpha1.RepositoryInformer,
|
||||
repoFactory repository.Factory,
|
||||
) (*RepositoryController, error) {
|
||||
controller := &RepositoryController{
|
||||
client: provisioningClient,
|
||||
repoLister: repoInformer.Lister(),
|
||||
repoSynced: repoInformer.Informer().HasSynced,
|
||||
repoFactory: repoFactory,
|
||||
client: provisioningClient,
|
||||
repoLister: repoInformer.Lister(),
|
||||
repoSynced: repoInformer.Informer().HasSynced,
|
||||
logger: logging.NewSLogLogger(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
})),
|
||||
@@ -139,6 +143,19 @@ func (c *RepositoryController) processRepository(ctx context.Context, key string
|
||||
"generation", repo.Generation,
|
||||
"observedGeneration", repo.Status.ObservedGeneration)
|
||||
|
||||
// These lines are here only for testing purposes until we use the real controller
|
||||
built, err := c.repoFactory.Build(ctx, repo)
|
||||
if err != nil {
|
||||
c.logger.Error("Failed to build repository instance", "error", err, "namespace", repo.Namespace, "name", repo.Name)
|
||||
} else {
|
||||
results, err := built.Test(ctx)
|
||||
if err != nil {
|
||||
c.logger.Error("Repository test failed", "error", err, "namespace", repo.Namespace, "name", repo.Name)
|
||||
} else {
|
||||
c.logger.Debug("Repository test results", "results", results, "namespace", repo.Namespace, "name", repo.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if repo.Generation != repo.Status.ObservedGeneration {
|
||||
repo.Status.ObservedGeneration = repo.Generation
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package provisioning
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -13,14 +14,20 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
authrt "github.com/grafana/grafana/apps/provisioning/pkg/auth"
|
||||
client "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned"
|
||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository/github"
|
||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository/local"
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
)
|
||||
|
||||
// provisioningControllerConfig contains the configuration that overlaps for the jobs and repo controllers
|
||||
type provisioningControllerConfig struct {
|
||||
provisioningClient *client.Clientset
|
||||
resyncInterval time.Duration
|
||||
repoFactory repository.Factory
|
||||
}
|
||||
|
||||
// expects:
|
||||
@@ -34,6 +41,9 @@ type provisioningControllerConfig struct {
|
||||
// tls_key_file =
|
||||
// tls_ca_file =
|
||||
// resync_interval =
|
||||
// repository_types =
|
||||
// home_path =
|
||||
// local_permitted_prefixes =
|
||||
func setupFromConfig(cfg *setting.Cfg) (controllerCfg *provisioningControllerConfig, err error) {
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("no configuration available")
|
||||
@@ -86,8 +96,15 @@ func setupFromConfig(cfg *setting.Cfg) (controllerCfg *provisioningControllerCon
|
||||
return nil, fmt.Errorf("failed to create provisioning client: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Replace with a real decrypter that uses the Grafana secret service
|
||||
repoFactory, err := setupRepoFactory(cfg, emptyValuesDecrypter, provisioningClient)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to setup repository getter: %w", err)
|
||||
}
|
||||
|
||||
return &provisioningControllerConfig{
|
||||
provisioningClient: provisioningClient,
|
||||
repoFactory: repoFactory,
|
||||
resyncInterval: operatorSec.Key("resync_interval").MustDuration(60 * time.Second),
|
||||
}, nil
|
||||
}
|
||||
@@ -120,3 +137,80 @@ func buildTLSConfig(insecure bool, certFile, keyFile, caFile string) (rest.TLSCl
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
// emptyValuesDecrypter is a decrypter that always returns empty values.
|
||||
// This is a temporary implementation and should be replaced with a real decrypter.
|
||||
// TODO: remove this and use a real decrypter that uses the Grafana secret service
|
||||
func emptyValuesDecrypter(r *provisioning.Repository) repository.SecureValues {
|
||||
return &emptyValues{}
|
||||
}
|
||||
|
||||
// emptyValues is a that always returns empty values.
|
||||
// This is a temporary implementation and should be replaced with a real decrypter.
|
||||
// TODO: remove this and use a real decrypter that uses the Grafana secret service
|
||||
type emptyValues struct{}
|
||||
|
||||
func (s *emptyValues) Token(ctx context.Context) (common.RawSecureValue, error) {
|
||||
return common.NewSecretValue(""), nil
|
||||
}
|
||||
|
||||
func (s *emptyValues) WebhookSecret(ctx context.Context) (common.RawSecureValue, error) {
|
||||
return common.NewSecretValue(""), nil
|
||||
}
|
||||
|
||||
func setupRepoFactory(
|
||||
cfg *setting.Cfg,
|
||||
decrypter repository.Decrypter,
|
||||
provisioningClient *client.Clientset,
|
||||
) (repository.Factory, error) {
|
||||
operatorSec := cfg.SectionWithEnvOverrides("operator")
|
||||
repoTypes := operatorSec.Key("repository_types").Strings("|")
|
||||
|
||||
// TODO: This depends on the different flavor of Grafana
|
||||
// https://github.com/grafana/git-ui-sync-project/issues/495
|
||||
extras := make([]repository.Extra, 0)
|
||||
alreadyRegistered := make(map[provisioning.RepositoryType]struct{})
|
||||
|
||||
for _, t := range repoTypes {
|
||||
if _, ok := alreadyRegistered[provisioning.RepositoryType(t)]; ok {
|
||||
continue
|
||||
}
|
||||
alreadyRegistered[provisioning.RepositoryType(t)] = struct{}{}
|
||||
|
||||
switch provisioning.RepositoryType(t) {
|
||||
case provisioning.GitHubRepositoryType:
|
||||
extras = append(extras, github.Extra(
|
||||
decrypter,
|
||||
github.ProvideFactory(),
|
||||
// TODO: we need to plug the webhook builder here for webhooks to be created in repository controller
|
||||
// https://github.com/grafana/git-ui-sync-project/issues/455
|
||||
nil,
|
||||
),
|
||||
)
|
||||
case provisioning.LocalRepositoryType:
|
||||
homePath := operatorSec.Key("home_path").String()
|
||||
if homePath == "" {
|
||||
return nil, fmt.Errorf("home_path is required in [operator] section for local repository type")
|
||||
}
|
||||
|
||||
permittedPrefixes := operatorSec.Key("local_permitted_prefixes").Strings("|")
|
||||
if len(permittedPrefixes) == 0 {
|
||||
return nil, fmt.Errorf("local_permitted_prefixes is required in [operator] section for local repository type")
|
||||
}
|
||||
|
||||
extras = append(extras, local.Extra(
|
||||
homePath,
|
||||
permittedPrefixes,
|
||||
))
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported repository type: %s", t)
|
||||
}
|
||||
}
|
||||
|
||||
repoFactory, err := repository.ProvideFactory(extras)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create repository factory: %w", err)
|
||||
}
|
||||
|
||||
return repoFactory, nil
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ func RunRepoController(opts standalone.BuildInfo, c *cli.Context, cfg *setting.C
|
||||
controller, err := controller.NewRepositoryController(
|
||||
controllerCfg.provisioningClient.ProvisioningV0alpha1(),
|
||||
repoInformer,
|
||||
controllerCfg.repoFactory,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create repository controller: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user