From 4a4af94d6c4682900d2d089e23a87472ed53476f Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Tue, 20 Apr 2021 13:00:48 +0300 Subject: [PATCH] Allow pre-bootstrap customisation of Flux components Signed-off-by: Stefan Prodan --- internal/bootstrap/bootstrap_plain_git.go | 49 +++++++++++++++++++++-- internal/utils/utils.go | 49 +++++++++++++++++++++++ 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/internal/bootstrap/bootstrap_plain_git.go b/internal/bootstrap/bootstrap_plain_git.go index 19fbae18..c932375d 100644 --- a/internal/bootstrap/bootstrap_plain_git.go +++ b/internal/bootstrap/bootstrap_plain_git.go @@ -19,6 +19,8 @@ package bootstrap import ( "context" "fmt" + "io/ioutil" + "os" "path/filepath" "strings" "time" @@ -29,6 +31,7 @@ import ( "sigs.k8s.io/cli-utils/pkg/object" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/kustomize/api/filesys" + "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/yaml" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1" @@ -152,10 +155,48 @@ func (b *PlainGitBootstrapper) ReconcileComponents(ctx context.Context, manifest // Conditionally install manifests if mustInstallManifests(ctx, b.kube, options.Namespace) { - b.logger.Actionf("installing components in %q namespace", options.Namespace) - kubectlArgs := []string{"apply", "-f", filepath.Join(b.git.Path(), manifests.Path)} - if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil { - return err + componentsYAML := filepath.Join(b.git.Path(), manifests.Path) + + // Apply components using any existing customisations + kfile := filepath.Join(filepath.Dir(componentsYAML), konfig.DefaultKustomizationFileName()) + if _, err := os.Stat(kfile); err == nil { + tmpDir, err := ioutil.TempDir("", "gotk-crds") + defer os.RemoveAll(tmpDir) + + // Extract the CRDs from the components manifest + crdsYAML := filepath.Join(tmpDir, "gotk-crds.yaml") + if err := utils.ExtractCRDs(componentsYAML, crdsYAML); err != nil { + return err + } + + // Apply the CRDs + b.logger.Actionf("installing toolkit.fluxcd.io CRDs") + kubectlArgs := []string{"apply", "-f", crdsYAML} + if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil { + return err + } + + // Wait for CRDs to be established + b.logger.Waitingf("waiting for CRDs to be reconciled") + kubectlArgs = []string{"wait", "--for", "condition=established", "-f", crdsYAML} + if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil { + return err + } + b.logger.Successf("CRDs reconciled successfully") + + // Apply the components and their patches + b.logger.Actionf("installing components in %q namespace", options.Namespace) + kubectlArgs = []string{"apply", "-k", filepath.Dir(componentsYAML)} + if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil { + return err + } + } else { + // Apply the CRDs and controllers + b.logger.Actionf("installing components in %q namespace", options.Namespace) + kubectlArgs := []string{"apply", "-f", componentsYAML} + if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil { + return err + } } b.logger.Successf("installed components") } diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 5cefc4c4..1229d792 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -22,6 +22,7 @@ import ( "context" "fmt" "io" + "io/ioutil" "os" "os/exec" "path/filepath" @@ -47,6 +48,16 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" + + helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" + imageautov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1" + imagereflectv1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1" + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1" + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" + "github.com/fluxcd/pkg/runtime/dependency" + "github.com/fluxcd/pkg/version" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/fluxcd/flux2/pkg/manifestgen/install" ) @@ -313,3 +324,41 @@ func CompatibleVersion(binary, target string) bool { } return binSv.Major() == targetSv.Major() && binSv.Minor() == targetSv.Minor() } + +func ExtractCRDs(inManifestPath, outManifestPath string) error { + manifests, err := ioutil.ReadFile(inManifestPath) + if err != nil { + return err + } + + crds := "" + reader := sigyaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifests), 2048) + + for { + var obj unstructured.Unstructured + err := reader.Decode(&obj) + if err == io.EOF { + break + } else if err != nil { + return err + } + + if obj.GetKind() == "CustomResourceDefinition" { + b, err := obj.MarshalJSON() + if err != nil { + return err + } + y, err := yaml.JSONToYAML(b) + if err != nil { + return err + } + crds += "---\n" + string(y) + } + } + + if crds == "" { + return fmt.Errorf("no CRDs found in %s", inManifestPath) + } + + return ioutil.WriteFile(outManifestPath, []byte(crds), os.ModePerm) +}