From f9b456858753da296158360bfda54bbdbd8f27d2 Mon Sep 17 00:00:00 2001 From: Danil Grigorev Date: Wed, 6 Dec 2023 19:30:55 +0100 Subject: [PATCH] Allow to utilize providers from clusterctl.yaml file in /config/clusterctl.yaml --- internal/controller/consts.go | 1 + internal/controller/phases.go | 36 ++++++++++++++++++++----- internal/controller/phases_test.go | 12 +++++++-- internal/controller/preflight_checks.go | 10 ++++++- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/internal/controller/consts.go b/internal/controller/consts.go index 0f62ade6..685939f1 100644 --- a/internal/controller/consts.go +++ b/internal/controller/consts.go @@ -27,4 +27,5 @@ const ( githubDomain = "github.com" gitlabHostPrefix = "gitlab." gitlabPackagesAPIPrefix = "/api/v4/projects/" + configPath = "/config/clusterctl.yaml" ) diff --git a/internal/controller/phases.go b/internal/controller/phases.go index edf7c0be..986c97bb 100644 --- a/internal/controller/phases.go +++ b/internal/controller/phases.go @@ -23,6 +23,7 @@ import ( "fmt" "io" "net/url" + "os" "strings" corev1 "k8s.io/api/core/v1" @@ -114,18 +115,35 @@ func (p *phaseReconciler) preflightChecks(ctx context.Context) (reconcile.Result // initializePhaseReconciler initializes phase reconciler. func (p *phaseReconciler) initializePhaseReconciler(ctx context.Context) (reconcile.Result, error) { - // Load provider's secret and config url. - reader, err := p.secretReader(ctx) - if err != nil { - return reconcile.Result{}, wrapPhaseError(err, "failed to load the secret reader") + path := configPath + if _, err := os.Stat(configPath); os.IsNotExist(err) { + path = "" + } else if err != nil { + return reconcile.Result{}, err } // Initialize a client for interacting with the clusterctl configuration. - p.configClient, err = configclient.New(ctx, "", configclient.InjectReader(reader)) + initConfig, err := configclient.New(ctx, path) + if err != nil { + return reconcile.Result{}, err + } + + providers, err := initConfig.Providers().List() if err != nil { return reconcile.Result{}, err } + reader, err := p.secretReader(ctx, providers...) + if err != nil { + return reconcile.Result{}, err + } + + // Load provider's secret and config url. + p.configClient, err = configclient.New(ctx, "", configclient.InjectReader(reader)) + if err != nil { + return reconcile.Result{}, wrapPhaseError(err, "failed to load the secret reader") + } + // Get returns the configuration for the provider with a given name/type. // This is done using clusterctl internal API types. p.providerConfig, err = p.configClient.Providers().Get(p.provider.GetName(), util.ClusterctlProviderType(p.provider)) @@ -197,7 +215,7 @@ func (p *phaseReconciler) load(ctx context.Context) (reconcile.Result, error) { // secretReader use clusterctl MemoryReader structure to store the configuration variables // that are obtained from a secret and try to set fetch url config. -func (p *phaseReconciler) secretReader(ctx context.Context) (configclient.Reader, error) { +func (p *phaseReconciler) secretReader(ctx context.Context, providers ...configclient.Provider) (configclient.Reader, error) { log := ctrl.LoggerFrom(ctx) mr := configclient.NewMemoryReader() @@ -222,6 +240,12 @@ func (p *phaseReconciler) secretReader(ctx context.Context) (configclient.Reader log.Info("No configuration secret was specified") } + for _, provider := range providers { + if _, err := mr.AddProvider(provider.Name(), provider.Type(), provider.URL()); err != nil { + return nil, err + } + } + // If provided store fetch config url in memory reader. if p.provider.GetSpec().FetchConfig != nil { if p.provider.GetSpec().FetchConfig.URL != "" { diff --git a/internal/controller/phases_test.go b/internal/controller/phases_test.go index 1ff9633d..2fcbb7fd 100644 --- a/internal/controller/phases_test.go +++ b/internal/controller/phases_test.go @@ -72,6 +72,8 @@ func TestSecretReader(t *testing.T) { testValue1 := "test-value1" testKey2 := "test-key2" testValue2 := "test-value2" + testKey3 := "test-key3" + testValue3 := "test-value3" g.Expect(fakeclient.Create(ctx, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -84,7 +86,7 @@ func TestSecretReader(t *testing.T) { }, })).To(Succeed()) - configreader, err := p.secretReader(context.TODO()) + configreader, err := p.secretReader(context.TODO(), configclient.NewProvider(testKey3, testValue3, clusterctlv1.CoreProviderType)) g.Expect(err).ToNot(HaveOccurred()) expectedValue1, err := configreader.Get(testKey1) @@ -97,7 +99,13 @@ func TestSecretReader(t *testing.T) { exptectedProviderData, err := configreader.Get("providers") g.Expect(err).ToNot(HaveOccurred()) - g.Expect(exptectedProviderData).To(Equal("- name: cluster-api\n type: CoreProvider\n url: https://example.com\n")) + g.Expect(exptectedProviderData).To(Equal(`- name: test-key3 + type: CoreProvider + url: test-value3 +- name: cluster-api + type: CoreProvider + url: https://example.com +`)) } func TestConfigmapRepository(t *testing.T) { diff --git a/internal/controller/preflight_checks.go b/internal/controller/preflight_checks.go index 16f86afd..8a25d255 100644 --- a/internal/controller/preflight_checks.go +++ b/internal/controller/preflight_checks.go @@ -19,6 +19,7 @@ package controller import ( "context" "fmt" + "os" "github.com/google/go-github/v52/github" "golang.org/x/oauth2" @@ -230,8 +231,15 @@ func coreProviderIsReady(ctx context.Context, c client.Client) (bool, error) { // The list of known providers can be found here: // https://github.com/kubernetes-sigs/cluster-api/blob/main/cmd/clusterctl/client/config/providers_client.go func isPredefinedProvider(ctx context.Context, providerName string, providerType clusterctlv1.ProviderType) (bool, error) { + path := configPath + if _, err := os.Stat(configPath); os.IsNotExist(err) { + path = "" + } else if err != nil { + return false, err + } + // Initialize a client that contains predefined providers only. - configClient, err := configclient.New(ctx, "") + configClient, err := configclient.New(ctx, path) if err != nil { return false, err }