mirror of
				https://github.com/fluxcd/flux2.git
				synced 2025-10-31 08:17:19 +08:00 
			
		
		
		
	Replace kubectl with Go server-side apply
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/bootstrap.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/bootstrap.yaml
									
									
									
									
										vendored
									
									
								
							| @ -4,7 +4,7 @@ on: | |||||||
|   push: |   push: | ||||||
|     branches: [ main ] |     branches: [ main ] | ||||||
|   pull_request: |   pull_request: | ||||||
|     branches: [ main ] |     branches: [ main, ssa ] | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   github: |   github: | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/e2e.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/e2e.yaml
									
									
									
									
										vendored
									
									
								
							| @ -4,7 +4,7 @@ on: | |||||||
|   push: |   push: | ||||||
|     branches: [ main ] |     branches: [ main ] | ||||||
|   pull_request: |   pull_request: | ||||||
|     branches: [ main ] |     branches: [ main, ssa ] | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   kind: |   kind: | ||||||
|  | |||||||
| @ -18,9 +18,7 @@ package main | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/json" |  | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/exec" |  | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/Masterminds/semver/v3" | 	"github.com/Masterminds/semver/v3" | ||||||
| @ -73,18 +71,11 @@ func init() { | |||||||
| } | } | ||||||
|  |  | ||||||
| func runCheckCmd(cmd *cobra.Command, args []string) error { | func runCheckCmd(cmd *cobra.Command, args []string) error { | ||||||
| 	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) |  | ||||||
| 	defer cancel() |  | ||||||
|  |  | ||||||
| 	logger.Actionf("checking prerequisites") | 	logger.Actionf("checking prerequisites") | ||||||
| 	checkFailed := false | 	checkFailed := false | ||||||
|  |  | ||||||
| 	fluxCheck() | 	fluxCheck() | ||||||
|  |  | ||||||
| 	if !kubectlCheck(ctx, ">=1.18.0-0") { |  | ||||||
| 		checkFailed = true |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if !kubernetesCheck(">=1.16.0-0") { | 	if !kubernetesCheck(">=1.16.0-0") { | ||||||
| 		checkFailed = true | 		checkFailed = true | ||||||
| 	} | 	} | ||||||
| @ -130,42 +121,6 @@ func fluxCheck() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func kubectlCheck(ctx context.Context, constraint string) bool { |  | ||||||
| 	_, err := exec.LookPath("kubectl") |  | ||||||
| 	if err != nil { |  | ||||||
| 		logger.Failuref("kubectl not found") |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	kubectlArgs := []string{"version", "--client", "--output", "json"} |  | ||||||
| 	output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logger.Failuref("kubectl version can't be determined") |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	kv := &kubectlVersion{} |  | ||||||
| 	if err = json.Unmarshal([]byte(output), kv); err != nil { |  | ||||||
| 		logger.Failuref("kubectl version output can't be unmarshalled") |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	v, err := version.ParseVersion(kv.ClientVersion.GitVersion) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logger.Failuref("kubectl version can't be parsed") |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	c, _ := semver.NewConstraint(constraint) |  | ||||||
| 	if !c.Check(v) { |  | ||||||
| 		logger.Failuref("kubectl version %s < %s", v.Original(), constraint) |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	logger.Successf("kubectl %s %s", v.String(), constraint) |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func kubernetesCheck(constraint string) bool { | func kubernetesCheck(constraint string) bool { | ||||||
| 	cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) | 	cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | |||||||
| @ -23,13 +23,11 @@ func TestCheckPre(t *testing.T) { | |||||||
| 		t.Fatalf("Error unmarshalling: %v", err.Error()) | 		t.Fatalf("Error unmarshalling: %v", err.Error()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	clientVersion := strings.TrimPrefix(versions["clientVersion"].GitVersion, "v") |  | ||||||
| 	serverVersion := strings.TrimPrefix(versions["serverVersion"].GitVersion, "v") | 	serverVersion := strings.TrimPrefix(versions["serverVersion"].GitVersion, "v") | ||||||
|  |  | ||||||
| 	cmd := cmdTestCase{ | 	cmd := cmdTestCase{ | ||||||
| 		args: "check --pre", | 		args: "check --pre", | ||||||
| 		assert: assertGoldenTemplateFile("testdata/check/check_pre.golden", map[string]string{ | 		assert: assertGoldenTemplateFile("testdata/check/check_pre.golden", map[string]string{ | ||||||
| 			"clientVersion": clientVersion, |  | ||||||
| 			"serverVersion": serverVersion, | 			"serverVersion": serverVersion, | ||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -41,13 +41,13 @@ If a previous version is installed, then an in-place upgrade will be performed.` | |||||||
|   flux install --version=latest --namespace=flux-system |   flux install --version=latest --namespace=flux-system | ||||||
|  |  | ||||||
|   # Install a specific version and a series of components |   # Install a specific version and a series of components | ||||||
|   flux install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller" |   flux install --version=v0.0.7 --components="source-controller,kustomize-controller" | ||||||
|  |  | ||||||
|   # Install Flux onto tainted Kubernetes nodes |   # Install Flux onto tainted Kubernetes nodes | ||||||
|   flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux |   flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux | ||||||
|  |  | ||||||
|   # Dry-run install with manifests preview |   # Dry-run install | ||||||
|   flux install --dry-run --verbose |   flux install --export | kubectl apply --dry-run=client -f-  | ||||||
|  |  | ||||||
|   # Write install manifests to file |   # Write install manifests to file | ||||||
|   flux install --export > flux-system.yaml`, |   flux install --export > flux-system.yaml`, | ||||||
| @ -102,6 +102,7 @@ func init() { | |||||||
| 		"list of toleration keys used to schedule the components pods onto nodes with matching taints") | 		"list of toleration keys used to schedule the components pods onto nodes with matching taints") | ||||||
| 	installCmd.Flags().MarkHidden("manifests") | 	installCmd.Flags().MarkHidden("manifests") | ||||||
| 	installCmd.Flags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64") | 	installCmd.Flags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64") | ||||||
|  | 	installCmd.Flags().MarkDeprecated("dry-run", "use 'flux install --export | kubectl apply --dry-run=client -f-'") | ||||||
| 	rootCmd.AddCommand(installCmd) | 	rootCmd.AddCommand(installCmd) | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -188,25 +189,19 @@ func installCmdRun(cmd *cobra.Command, args []string) error { | |||||||
|  |  | ||||||
| 	logger.Successf("manifests build completed") | 	logger.Successf("manifests build completed") | ||||||
| 	logger.Actionf("installing components in %s namespace", rootArgs.namespace) | 	logger.Actionf("installing components in %s namespace", rootArgs.namespace) | ||||||
| 	applyOutput := utils.ModeStderrOS |  | ||||||
| 	if rootArgs.verbose { |  | ||||||
| 		applyOutput = utils.ModeOS |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	kubectlArgs := []string{"apply", "-f", filepath.Join(tmpDir, manifest.Path)} |  | ||||||
| 	if installArgs.dryRun { |  | ||||||
| 		kubectlArgs = append(kubectlArgs, "--dry-run=client") |  | ||||||
| 		applyOutput = utils.ModeOS |  | ||||||
| 	} |  | ||||||
| 	if _, err := utils.ExecKubectlCommand(ctx, applyOutput, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil { |  | ||||||
| 		return fmt.Errorf("install failed: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if installArgs.dryRun { | 	if installArgs.dryRun { | ||||||
| 		logger.Successf("install dry-run finished") | 		logger.Successf("install dry-run finished") | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	applyOutput, err := utils.Apply(ctx, rootArgs.kubeconfig, rootArgs.kubecontext, filepath.Join(tmpDir, manifest.Path)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("install failed: %w", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fmt.Fprintln(os.Stderr, applyOutput) | ||||||
|  |  | ||||||
| 	kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) | 	kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("install failed: %w", err) | 		return fmt.Errorf("install failed: %w", err) | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								cmd/flux/testdata/check/check_pre.golden
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								cmd/flux/testdata/check/check_pre.golden
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,3 @@ | |||||||
| ► checking prerequisites | ► checking prerequisites | ||||||
| ✔ kubectl {{ .clientVersion }} >=1.18.0-0 |  | ||||||
| ✔ Kubernetes {{ .serverVersion }} >=1.16.0-0 | ✔ Kubernetes {{ .serverVersion }} >=1.16.0-0 | ||||||
| ✔ prerequisites checks passed | ✔ prerequisites checks passed | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
								
							| @ -14,12 +14,13 @@ require ( | |||||||
| 	github.com/fluxcd/notification-controller/api v0.17.0 | 	github.com/fluxcd/notification-controller/api v0.17.0 | ||||||
| 	github.com/fluxcd/pkg/apis/meta v0.10.0 | 	github.com/fluxcd/pkg/apis/meta v0.10.0 | ||||||
| 	github.com/fluxcd/pkg/runtime v0.12.0 | 	github.com/fluxcd/pkg/runtime v0.12.0 | ||||||
|  | 	github.com/fluxcd/pkg/ssa v0.0.1 | ||||||
| 	github.com/fluxcd/pkg/ssh v0.0.5 | 	github.com/fluxcd/pkg/ssh v0.0.5 | ||||||
| 	github.com/fluxcd/pkg/untar v0.0.5 | 	github.com/fluxcd/pkg/untar v0.0.5 | ||||||
| 	github.com/fluxcd/pkg/version v0.0.1 | 	github.com/fluxcd/pkg/version v0.0.1 | ||||||
| 	github.com/fluxcd/source-controller/api v0.16.0 | 	github.com/fluxcd/source-controller/api v0.16.0 | ||||||
| 	github.com/go-git/go-git/v5 v5.4.2 | 	github.com/go-git/go-git/v5 v5.4.2 | ||||||
| 	github.com/google/go-cmp v0.5.5 | 	github.com/google/go-cmp v0.5.6 | ||||||
| 	github.com/google/go-containerregistry v0.2.0 | 	github.com/google/go-containerregistry v0.2.0 | ||||||
| 	github.com/manifoldco/promptui v0.7.0 | 	github.com/manifoldco/promptui v0.7.0 | ||||||
| 	github.com/mattn/go-shellwords v1.0.12 | 	github.com/mattn/go-shellwords v1.0.12 | ||||||
| @ -35,7 +36,7 @@ require ( | |||||||
| 	sigs.k8s.io/cli-utils v0.25.1-0.20210608181808-f3974341173a | 	sigs.k8s.io/cli-utils v0.25.1-0.20210608181808-f3974341173a | ||||||
| 	sigs.k8s.io/controller-runtime v0.10.1 | 	sigs.k8s.io/controller-runtime v0.10.1 | ||||||
| 	sigs.k8s.io/kustomize/api v0.8.10 | 	sigs.k8s.io/kustomize/api v0.8.10 | ||||||
| 	sigs.k8s.io/yaml v1.2.0 | 	sigs.k8s.io/yaml v1.3.0 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // drop LGPL dependency manifoldco/promptui -> juju/ansiterm | // drop LGPL dependency manifoldco/promptui -> juju/ansiterm | ||||||
|  | |||||||
| @ -175,41 +175,14 @@ func (b *PlainGitBootstrapper) ReconcileComponents(ctx context.Context, manifest | |||||||
| 		// Apply components using any existing customisations | 		// Apply components using any existing customisations | ||||||
| 		kfile := filepath.Join(filepath.Dir(componentsYAML), konfig.DefaultKustomizationFileName()) | 		kfile := filepath.Join(filepath.Dir(componentsYAML), konfig.DefaultKustomizationFileName()) | ||||||
| 		if _, err := os.Stat(kfile); err == nil { | 		if _, err := os.Stat(kfile); err == nil { | ||||||
| 			tmpDir, err := os.MkdirTemp("", "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 | 			// Apply the components and their patches | ||||||
| 			b.logger.Actionf("installing components in %q namespace", options.Namespace) | 			b.logger.Actionf("installing components in %q namespace", options.Namespace) | ||||||
| 			kubectlArgs = []string{"apply", "-k", filepath.Dir(componentsYAML)} | 			if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, kfile); err != nil { | ||||||
| 			if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil { |  | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			// Apply the CRDs and controllers | 			// Apply the CRDs and controllers | ||||||
| 			b.logger.Actionf("installing components in %q namespace", options.Namespace) | 			if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, componentsYAML); err != nil { | ||||||
| 			kubectlArgs := []string{"apply", "-f", componentsYAML} |  | ||||||
| 			if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil { |  | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -336,10 +309,10 @@ func (b *PlainGitBootstrapper) ReconcileSyncConfig(ctx context.Context, options | |||||||
|  |  | ||||||
| 	// Apply to cluster | 	// Apply to cluster | ||||||
| 	b.logger.Actionf("applying sync manifests") | 	b.logger.Actionf("applying sync manifests") | ||||||
| 	kubectlArgs := []string{"apply", "-k", filepath.Join(b.git.Path(), filepath.Dir(kusManifests.Path))} | 	if _, err := utils.Apply(ctx, b.kubeconfig, b.kubecontext, filepath.Join(b.git.Path(), kusManifests.Path)); err != nil { | ||||||
| 	if _, err = utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, b.kubeconfig, b.kubecontext, kubectlArgs...); err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b.logger.Successf("reconciled sync configuration") | 	b.logger.Successf("reconciled sync configuration") | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
|  | |||||||
							
								
								
									
										81
									
								
								internal/utils/apply.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								internal/utils/apply.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | |||||||
|  | package utils | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/fluxcd/pkg/ssa" | ||||||
|  | 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||||||
|  | 	"sigs.k8s.io/cli-utils/pkg/kstatus/polling" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/client" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/client/apiutil" | ||||||
|  | 	"sigs.k8s.io/kustomize/api/konfig" | ||||||
|  |  | ||||||
|  | 	"github.com/fluxcd/flux2/pkg/manifestgen/kustomization" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Apply is the equivalent of 'kubectl apply --server-side -f'. | ||||||
|  | // If the given manifest is a kustomization.yaml, then apply performs the equivalent of 'kubectl apply --server-side -k'. | ||||||
|  | func Apply(ctx context.Context, kubeConfigPath string, kubeContext string, manifestPath string) (string, error) { | ||||||
|  | 	cfg, err := KubeConfig(kubeConfigPath, kubeContext) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	restMapper, err := apiutil.NewDynamicRESTMapper(cfg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	kubeClient, err := client.New(cfg, client.Options{Mapper: restMapper}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	kubePoller := polling.NewStatusPoller(kubeClient, restMapper) | ||||||
|  |  | ||||||
|  | 	resourceManager := ssa.NewResourceManager(kubeClient, kubePoller, ssa.Owner{ | ||||||
|  | 		Field: "flux", | ||||||
|  | 		Group: "fluxcd.io", | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	objs, err := readObjects(manifestPath) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(objs) < 1 { | ||||||
|  | 		return "", fmt.Errorf("no Kubernetes objects found at: %s", manifestPath) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	changeSet, err := resourceManager.ApplyAllStaged(ctx, objs, false, time.Minute) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return changeSet.String(), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func readObjects(manifestPath string) ([]*unstructured.Unstructured, error) { | ||||||
|  | 	if _, err := os.Stat(manifestPath); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if filepath.Base(manifestPath) == konfig.DefaultKustomizationFileName() { | ||||||
|  | 		resources, err := kustomization.Build(filepath.Dir(manifestPath)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		return ssa.ReadObjects(bytes.NewReader(resources)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ms, err := os.Open(manifestPath) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer ms.Close() | ||||||
|  |  | ||||||
|  | 	return ssa.ReadObjects(bufio.NewReader(ms)) | ||||||
|  | } | ||||||
| @ -25,13 +25,11 @@ import ( | |||||||
| 	"path" | 	"path" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync" |  | ||||||
|  |  | ||||||
| 	"sigs.k8s.io/kustomize/api/filesys" |  | ||||||
| 	"sigs.k8s.io/kustomize/api/krusty" |  | ||||||
| 	kustypes "sigs.k8s.io/kustomize/api/types" |  | ||||||
|  |  | ||||||
| 	"github.com/fluxcd/pkg/untar" | 	"github.com/fluxcd/pkg/untar" | ||||||
|  | 	"sigs.k8s.io/kustomize/api/filesys" | ||||||
|  |  | ||||||
|  | 	"github.com/fluxcd/flux2/pkg/manifestgen/kustomization" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func fetch(ctx context.Context, url, version, dir string) error { | func fetch(ctx context.Context, url, version, dir string) error { | ||||||
| @ -114,56 +112,13 @@ func generate(base string, options Options) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| var kustomizeBuildMutex sync.Mutex |  | ||||||
|  |  | ||||||
| func build(base, output string) error { | func build(base, output string) error { | ||||||
| 	// TODO(stefan): temporary workaround for concurrent map read and map write bug | 	resources, err := kustomization.Build(base) | ||||||
| 	// https://github.com/kubernetes-sigs/kustomize/issues/3659 | 	if err != nil { | ||||||
| 	kustomizeBuildMutex.Lock() | 		return err | ||||||
| 	defer kustomizeBuildMutex.Unlock() | 	} | ||||||
|  |  | ||||||
| 	kfile := filepath.Join(base, "kustomization.yaml") |  | ||||||
|  |  | ||||||
| 	fs := filesys.MakeFsOnDisk() | 	fs := filesys.MakeFsOnDisk() | ||||||
| 	if !fs.Exists(kfile) { |  | ||||||
| 		return fmt.Errorf("%s not found", kfile) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// TODO(hidde): work around for a bug in kustomize causing it to |  | ||||||
| 	//  not properly handle absolute paths on Windows. |  | ||||||
| 	//  Convert the path to a relative path to the working directory |  | ||||||
| 	//  as a temporary fix: |  | ||||||
| 	//  https://github.com/kubernetes-sigs/kustomize/issues/2789 |  | ||||||
| 	if filepath.IsAbs(base) { |  | ||||||
| 		wd, err := os.Getwd() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		base, err = filepath.Rel(wd, base) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	buildOptions := &krusty.Options{ |  | ||||||
| 		DoLegacyResourceSort: true, |  | ||||||
| 		LoadRestrictions:     kustypes.LoadRestrictionsNone, |  | ||||||
| 		AddManagedbyLabel:    false, |  | ||||||
| 		DoPrune:              false, |  | ||||||
| 		PluginConfig:         kustypes.DisabledPluginConfig(), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	k := krusty.MakeKustomizer(buildOptions) |  | ||||||
| 	m, err := k.Run(fs, base) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	resources, err := m.AsYaml() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := fs.WriteFile(output, resources); err != nil { | 	if err := fs.WriteFile(output, resources); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -17,10 +17,14 @@ limitations under the License. | |||||||
| package kustomization | package kustomization | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	"sigs.k8s.io/kustomize/api/filesys" | ||||||
| 	"sigs.k8s.io/kustomize/api/konfig" | 	"sigs.k8s.io/kustomize/api/konfig" | ||||||
|  | 	"sigs.k8s.io/kustomize/api/krusty" | ||||||
| 	"sigs.k8s.io/kustomize/api/provider" | 	"sigs.k8s.io/kustomize/api/provider" | ||||||
| 	kustypes "sigs.k8s.io/kustomize/api/types" | 	kustypes "sigs.k8s.io/kustomize/api/types" | ||||||
| 	"sigs.k8s.io/yaml" | 	"sigs.k8s.io/yaml" | ||||||
| @ -28,6 +32,8 @@ import ( | |||||||
| 	"github.com/fluxcd/flux2/pkg/manifestgen" | 	"github.com/fluxcd/flux2/pkg/manifestgen" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // Generate scans the given directory for Kubernetes manifests and creates a kustomization.yaml | ||||||
|  | // including all discovered manifests as resources. | ||||||
| func Generate(options Options) (*manifestgen.Manifest, error) { | func Generate(options Options) (*manifestgen.Manifest, error) { | ||||||
| 	kfile := filepath.Join(options.TargetPath, konfig.DefaultKustomizationFileName()) | 	kfile := filepath.Join(options.TargetPath, konfig.DefaultKustomizationFileName()) | ||||||
| 	abskfile := filepath.Join(options.BaseDir, kfile) | 	abskfile := filepath.Join(options.BaseDir, kfile) | ||||||
| @ -121,3 +127,57 @@ func Generate(options Options) (*manifestgen.Manifest, error) { | |||||||
| 		Content: string(kd), | 		Content: string(kd), | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | var kustomizeBuildMutex sync.Mutex | ||||||
|  |  | ||||||
|  | // Build takes a Kustomize overlays and returns the resulting manifests as multi-doc YAML. | ||||||
|  | func Build(base string) ([]byte, error) { | ||||||
|  | 	// TODO(stefan): temporary workaround for concurrent map read and map write bug | ||||||
|  | 	// https://github.com/kubernetes-sigs/kustomize/issues/3659 | ||||||
|  | 	kustomizeBuildMutex.Lock() | ||||||
|  | 	defer kustomizeBuildMutex.Unlock() | ||||||
|  |  | ||||||
|  | 	kfile := filepath.Join(base, konfig.DefaultKustomizationFileName()) | ||||||
|  |  | ||||||
|  | 	fs := filesys.MakeFsOnDisk() | ||||||
|  | 	if !fs.Exists(kfile) { | ||||||
|  | 		return nil, fmt.Errorf("%s not found", kfile) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// TODO(hidde): work around for a bug in kustomize causing it to | ||||||
|  | 	//  not properly handle absolute paths on Windows. | ||||||
|  | 	//  Convert the path to a relative path to the working directory | ||||||
|  | 	//  as a temporary fix: | ||||||
|  | 	//  https://github.com/kubernetes-sigs/kustomize/issues/2789 | ||||||
|  | 	if filepath.IsAbs(base) { | ||||||
|  | 		wd, err := os.Getwd() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		base, err = filepath.Rel(wd, base) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	buildOptions := &krusty.Options{ | ||||||
|  | 		DoLegacyResourceSort: true, | ||||||
|  | 		LoadRestrictions:     kustypes.LoadRestrictionsNone, | ||||||
|  | 		AddManagedbyLabel:    false, | ||||||
|  | 		DoPrune:              false, | ||||||
|  | 		PluginConfig:         kustypes.DisabledPluginConfig(), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	k := krusty.MakeKustomizer(buildOptions) | ||||||
|  | 	m, err := k.Run(fs, base) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	resources, err := m.AsYaml() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return resources, nil | ||||||
|  | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Stefan Prodan
					Stefan Prodan