-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add fallback to kubectl kustomize if kustomize binary isn't present #4484
Changes from 1 commit
26ceb9e
0c8e998
aa3a086
2fa2c99
c5a49d6
1a00075
61796f3
9d6967d
1853c63
095909f
8706968
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ var ( | |
DefaultKustomizePath = "." | ||
kustomizeFilePaths = []string{"kustomization.yaml", "kustomization.yml", "Kustomization"} | ||
basePath = "base" | ||
kustomizeBinaryCheck = kustomizeBinaryExists // For testing | ||
) | ||
|
||
// kustomization is the content of a kustomization.yaml file. | ||
|
@@ -100,9 +101,13 @@ type KustomizeDeployer struct { | |
BuildArgs []string | ||
globalConfig string | ||
addSkaffoldLabels bool | ||
useKubectl bool | ||
} | ||
|
||
func NewKustomizeDeployer(runCtx *runcontext.RunContext) *KustomizeDeployer { | ||
// if user has kustomize binary, prioritize that over kubectl kustomize | ||
useKubectl := !kustomizeBinaryCheck() | ||
|
||
return &KustomizeDeployer{ | ||
KustomizeDeploy: runCtx.Cfg.Deploy.KustomizeDeploy, | ||
kubectl: deploy.CLI{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems odd to pass in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I should rename |
||
|
@@ -114,9 +119,20 @@ func NewKustomizeDeployer(runCtx *runcontext.RunContext) *KustomizeDeployer { | |
BuildArgs: runCtx.Cfg.Deploy.KustomizeDeploy.BuildArgs, | ||
globalConfig: runCtx.Opts.GlobalConfig, | ||
addSkaffoldLabels: runCtx.Opts.AddSkaffoldLabels, | ||
useKubectl: useKubectl, | ||
} | ||
} | ||
|
||
// Check for existence of kustomize binary in user's PATH | ||
func kustomizeBinaryExists() bool { | ||
cmd := exec.Command("which", "kustomize") | ||
MarlonGamez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if err := util.RunCmd(cmd); err != nil { | ||
return false | ||
} | ||
|
||
return true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might also be worth logging the version of the binary to the user. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if they have an old old version of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i read this PR as if users have kustomize binary use it even if its older version. |
||
} | ||
|
||
// Labels returns the labels specific to kustomize. | ||
func (k *KustomizeDeployer) Labels() map[string]string { | ||
return map[string]string{ | ||
|
@@ -366,8 +382,16 @@ func pathExistsLocally(filename string, workingDir string) (bool, os.FileMode) { | |
func (k *KustomizeDeployer) readManifests(ctx context.Context) (deploy.ManifestList, error) { | ||
var manifests deploy.ManifestList | ||
for _, kustomizePath := range k.KustomizePaths { | ||
cmd := exec.CommandContext(ctx, "kustomize", buildCommandArgs(k.BuildArgs, kustomizePath)...) | ||
out, err := util.RunCmdOut(cmd) | ||
var out []byte | ||
var err error | ||
|
||
if k.useKubectl { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth noting that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, this could manifest through build args being rejected by the binary depending on which version the user thinks they're using - but I think that's ok left up to them to handle? we can't really know which version of kustomize a user is targeting with their arguments without asking them, so I think it's ok to assume that whatever they pass will be compatible with whatever kustomize binary we end up using. this is of course assuming that they can easily know which one we'll select based on good documentation :) |
||
out, err = k.kubectl.Kustomize(ctx, buildCommandArgs(k.BuildArgs, kustomizePath)) | ||
} else { | ||
cmd := exec.CommandContext(ctx, "kustomize", append([]string{"build"}, buildCommandArgs(k.BuildArgs, kustomizePath)...)...) | ||
out, err = util.RunCmdOut(cmd) | ||
} | ||
|
||
if err != nil { | ||
return nil, fmt.Errorf("kustomize build: %w", err) | ||
} | ||
|
@@ -382,7 +406,6 @@ func (k *KustomizeDeployer) readManifests(ctx context.Context) (deploy.ManifestL | |
|
||
func buildCommandArgs(buildArgs []string, kustomizePath string) []string { | ||
var args []string | ||
args = append(args, "build") | ||
|
||
if len(buildArgs) > 0 { | ||
for _, v := range buildArgs { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,20 +34,22 @@ import ( | |
|
||
func TestKustomizeDeploy(t *testing.T) { | ||
tests := []struct { | ||
description string | ||
cfg *latest.KustomizeDeploy | ||
builds []build.Artifact | ||
commands util.Command | ||
shouldErr bool | ||
forceDeploy bool | ||
description string | ||
cfg *latest.KustomizeDeploy | ||
builds []build.Artifact | ||
commands util.Command | ||
shouldErr bool | ||
forceDeploy bool | ||
useMockKustomizeCheck bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From a reading perspective, it might be more intuitive for this to be |
||
}{ | ||
{ | ||
description: "no manifest", | ||
cfg: &latest.KustomizeDeploy{ | ||
KustomizePaths: []string{"."}, | ||
}, | ||
commands: testutil. | ||
CmdRunOut("kubectl version --client -ojson", kubectlVersion112). | ||
CmdRun("which kustomize"). | ||
AndRunOut("kubectl version --client -ojson", kubectlVersion112). | ||
AndRunOut("kustomize build .", ""), | ||
}, | ||
{ | ||
|
@@ -56,7 +58,8 @@ func TestKustomizeDeploy(t *testing.T) { | |
KustomizePaths: []string{"."}, | ||
}, | ||
commands: testutil. | ||
CmdRunOut("kubectl version --client -ojson", kubectlVersion112). | ||
CmdRun("which kustomize"). | ||
AndRunOut("kubectl version --client -ojson", kubectlVersion112). | ||
AndRunOut("kustomize build .", deploymentWebYAML). | ||
AndRun("kubectl --context kubecontext --namespace testNamespace apply -f - --force --grace-period=0"), | ||
builds: []build.Artifact{{ | ||
|
@@ -71,7 +74,8 @@ func TestKustomizeDeploy(t *testing.T) { | |
KustomizePaths: []string{"a", "b"}, | ||
}, | ||
commands: testutil. | ||
CmdRunOut("kubectl version --client -ojson", kubectlVersion112). | ||
CmdRun("which kustomize"). | ||
AndRunOut("kubectl version --client -ojson", kubectlVersion112). | ||
AndRunOut("kustomize build a", deploymentWebYAML). | ||
AndRunOut("kustomize build b", deploymentAppYAML). | ||
AndRun("kubectl --context kubecontext --namespace testNamespace apply -f - --force --grace-period=0"), | ||
|
@@ -87,10 +91,41 @@ func TestKustomizeDeploy(t *testing.T) { | |
}, | ||
forceDeploy: true, | ||
}, | ||
{ | ||
description: "built-in kubectl kustomize", | ||
cfg: &latest.KustomizeDeploy{ | ||
KustomizePaths: []string{"a", "b"}, | ||
}, | ||
commands: testutil. | ||
CmdRunOut("kubectl version --client -ojson", kubectlVersion118). | ||
AndRunOut("kubectl --context kubecontext --namespace testNamespace kustomize a", deploymentWebYAML). | ||
AndRunOut("kubectl --context kubecontext --namespace testNamespace kustomize b", deploymentAppYAML). | ||
AndRun("kubectl --context kubecontext --namespace testNamespace apply -f - --force --grace-period=0"), | ||
builds: []build.Artifact{ | ||
{ | ||
ImageName: "leeroy-web", | ||
Tag: "leeroy-web:123", | ||
}, | ||
{ | ||
ImageName: "leeroy-app", | ||
Tag: "leeroy-app:123", | ||
}, | ||
}, | ||
forceDeploy: true, | ||
useMockKustomizeCheck: true, | ||
}, | ||
} | ||
|
||
mockKustomizeCheck := func() bool { | ||
return false | ||
} | ||
|
||
for _, test := range tests { | ||
testutil.Run(t, test.description, func(t *testutil.T) { | ||
t.Override(&util.DefaultExecCommand, test.commands) | ||
if test.useMockKustomizeCheck { | ||
t.Override(&kustomizeBinaryCheck, mockKustomizeCheck) | ||
} | ||
t.NewTempDir(). | ||
Chdir() | ||
|
||
|
@@ -131,7 +166,8 @@ func TestKustomizeCleanup(t *testing.T) { | |
KustomizePaths: []string{tmpDir.Root()}, | ||
}, | ||
commands: testutil. | ||
CmdRunOut("kustomize build "+tmpDir.Root(), deploymentWebYAML). | ||
CmdRun("which kustomize"). | ||
AndRunOut("kustomize build "+tmpDir.Root(), deploymentWebYAML). | ||
AndRun("kubectl --context kubecontext --namespace testNamespace delete --ignore-not-found=true -f -"), | ||
}, | ||
{ | ||
|
@@ -140,7 +176,8 @@ func TestKustomizeCleanup(t *testing.T) { | |
KustomizePaths: tmpDir.Paths("a", "b"), | ||
}, | ||
commands: testutil. | ||
CmdRunOut("kustomize build "+tmpDir.Path("a"), deploymentWebYAML). | ||
CmdRun("which kustomize"). | ||
AndRunOut("kustomize build "+tmpDir.Path("a"), deploymentWebYAML). | ||
AndRunOut("kustomize build "+tmpDir.Path("b"), deploymentAppYAML). | ||
AndRun("kubectl --context kubecontext --namespace testNamespace delete --ignore-not-found=true -f -"), | ||
}, | ||
|
@@ -150,7 +187,8 @@ func TestKustomizeCleanup(t *testing.T) { | |
KustomizePaths: []string{tmpDir.Root()}, | ||
}, | ||
commands: testutil. | ||
CmdRunOut("kustomize build "+tmpDir.Root(), deploymentWebYAML). | ||
CmdRun("which kustomize"). | ||
AndRunOut("kustomize build "+tmpDir.Root(), deploymentWebYAML). | ||
AndRunErr("kubectl --context kubecontext --namespace testNamespace delete --ignore-not-found=true -f -", errors.New("BUG")), | ||
shouldErr: true, | ||
}, | ||
|
@@ -159,11 +197,9 @@ func TestKustomizeCleanup(t *testing.T) { | |
cfg: &latest.KustomizeDeploy{ | ||
KustomizePaths: []string{tmpDir.Root()}, | ||
}, | ||
commands: testutil.CmdRunOutErr( | ||
"kustomize build "+tmpDir.Root(), | ||
"", | ||
errors.New("BUG"), | ||
), | ||
commands: testutil. | ||
CmdRun("which kustomize"). | ||
AndRunOutErr("kustomize build "+tmpDir.Root(), "", errors.New("BUG")), | ||
shouldErr: true, | ||
}, | ||
} | ||
|
@@ -415,49 +451,49 @@ func TestKustomizeBuildCommandArgs(t *testing.T) { | |
description: "no BuildArgs, empty KustomizePaths ", | ||
buildArgs: []string{}, | ||
kustomizePath: "", | ||
expectedArgs: []string{"build"}, | ||
expectedArgs: nil, | ||
}, | ||
{ | ||
description: "One BuildArg, empty KustomizePaths", | ||
buildArgs: []string{"--foo"}, | ||
kustomizePath: "", | ||
expectedArgs: []string{"build", "--foo"}, | ||
expectedArgs: []string{"--foo"}, | ||
}, | ||
{ | ||
description: "no BuildArgs, non-empty KustomizePaths", | ||
buildArgs: []string{}, | ||
kustomizePath: "foo", | ||
expectedArgs: []string{"build", "foo"}, | ||
expectedArgs: []string{"foo"}, | ||
}, | ||
{ | ||
description: "One BuildArg, non-empty KustomizePaths", | ||
buildArgs: []string{"--foo"}, | ||
kustomizePath: "bar", | ||
expectedArgs: []string{"build", "--foo", "bar"}, | ||
expectedArgs: []string{"--foo", "bar"}, | ||
}, | ||
{ | ||
description: "Multiple BuildArg, empty KustomizePaths", | ||
buildArgs: []string{"--foo", "--bar"}, | ||
kustomizePath: "", | ||
expectedArgs: []string{"build", "--foo", "--bar"}, | ||
expectedArgs: []string{"--foo", "--bar"}, | ||
}, | ||
{ | ||
description: "Multiple BuildArg with spaces, empty KustomizePaths", | ||
buildArgs: []string{"--foo bar", "--baz"}, | ||
kustomizePath: "", | ||
expectedArgs: []string{"build", "--foo", "bar", "--baz"}, | ||
expectedArgs: []string{"--foo", "bar", "--baz"}, | ||
}, | ||
{ | ||
description: "Multiple BuildArg with spaces, non-empty KustomizePaths", | ||
buildArgs: []string{"--foo bar", "--baz"}, | ||
kustomizePath: "barfoo", | ||
expectedArgs: []string{"build", "--foo", "bar", "--baz", "barfoo"}, | ||
expectedArgs: []string{"--foo", "bar", "--baz", "barfoo"}, | ||
}, | ||
{ | ||
description: "Multiple BuildArg no spaces, non-empty KustomizePaths", | ||
buildArgs: []string{"--foo", "bar", "--baz"}, | ||
kustomizePath: "barfoo", | ||
expectedArgs: []string{"build", "--foo", "bar", "--baz", "barfoo"}, | ||
expectedArgs: []string{"--foo", "bar", "--baz", "barfoo"}, | ||
}, | ||
} | ||
|
||
|
@@ -646,7 +682,8 @@ spec: | |
testutil.Run(t, test.description, func(t *testutil.T) { | ||
var kustomizationPaths []string | ||
fakeCmd := testutil. | ||
CmdRunOut("kubectl version --client -ojson", kubectlVersion112) | ||
CmdRun("which kustomize"). | ||
AndRunOut("kubectl version --client -ojson", kubectlVersion112) | ||
for _, kustomizationCall := range test.kustomizations { | ||
fakeCmd.AndRunOut("kustomize build "+kustomizationCall.folder, kustomizationCall.buildResult) | ||
kustomizationPaths = append(kustomizationPaths, kustomizationCall.folder) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also need to check that kubectl version ≥ 1.14 too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch