Skip to content
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

Sanity check for kpt/kustomize preinstalled version #4959

Merged
merged 1 commit into from
Oct 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ require (
go.uber.org/multierr v1.4.0 // indirect
go.uber.org/zap v1.12.0 // indirect
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
golang.org/x/mod v0.3.0
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
golang.org/x/sys v0.0.0-20200523222454-059865788121
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
Expand Down
66 changes: 66 additions & 0 deletions pkg/skaffold/deploy/kpt/kpt.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"regexp"
"strings"

"golang.org/x/mod/semver"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/kustomize/kyaml/fn/framework"
k8syaml "sigs.k8s.io/yaml"
Expand All @@ -49,6 +50,13 @@ const (
tmpKustomizeDir = ".kustomize"
kptFnAnnotation = "config.kubernetes.io/function"
kptFnLocalConfig = "config.kubernetes.io/local-config"

kptDownloadLink = "https://googlecontainertools.github.io/kpt/installation/"
kptMinVersion = "0.34.0"

kustomizeDownloadLink = "https://kubernetes-sigs.github.io/kustomize/installation/"
kustomizeMinVersion = "v3.2.3"
kustomizeVersionRegexP = `{Version:(\S+) GitCommit:\S+ BuildDate:\d{4}-\d{2}-\d{2}T\d\d:\d\d:\d\dZ GoOs:\S+ GoArch:\S+}`
)

// Deployer deploys workflows with kpt CLI
Expand All @@ -70,10 +78,65 @@ func NewDeployer(cfg types.Config, labels map[string]string) *Deployer {
}
}

var sanityCheck = versionCheck

// sanityCheck guarantees the kpt and kustomize versions are compatible with skaffold.
func versionCheck(dir string) error {
yuwenma marked this conversation as resolved.
Show resolved Hide resolved
kptCmd := exec.Command("kpt", "version")
out, err := util.RunCmdOut(kptCmd)
if err != nil {
return fmt.Errorf("kpt is not installed yet\nSee kpt installation: %v",
kptDownloadLink)
}
version := strings.TrimSuffix(string(out), "\n")
// kpt follows semver but does not have "v" prefix.
if !semver.IsValid("v" + version) {
return fmt.Errorf("unknown kpt version %v\nPlease upgrade your "+
"local kpt CLI to a version >= %v\nSee kpt installation: %v",
string(out), kptMinVersion, kptDownloadLink)
}
if semver.Compare("v"+version, "v"+kptMinVersion) < 0 {
return fmt.Errorf("you are using kpt %q\nPlease update your kpt version to"+
" >= %v\nSee kpt installation: %v", version[0], kptMinVersion, kptDownloadLink)
}

// Users can choose not to use kustomize in kpt deployer mode. We only check the kustomize
// version when kustomization.yaml config is directed under .deploy.kpt.dir path.
_, err = kustomize.FindKustomizationConfig(dir)
if err == nil {
kustomizeCmd := exec.Command("kustomize", "version")
out, err := util.RunCmdOut(kustomizeCmd)
if err != nil {
return fmt.Errorf("kustomize is not installed yet\nSee kpt installation: %v",
kustomizeDownloadLink)
}
versionInfo := strings.TrimSuffix(string(out), "\n")
// Kustomize version information is in the form of
// {Version:$VERSION GitCommit:$COMMIT BuildDate:1970-01-01T00:00:00Z GoOs:darwin GoArch:amd64}
re := regexp.MustCompile(kustomizeVersionRegexP)
match := re.FindStringSubmatch(versionInfo)
if len(match) != 2 {
return fmt.Errorf("unknown kustomize version %v\nPlease upgrade your "+
"local kustomize CLI to a version >= %v\nSee kustomize installation: %v",
string(out), kustomizeMinVersion, kustomizeDownloadLink)
}
if !semver.IsValid(match[1]) || semver.Compare(match[1], kustomizeMinVersion) < 0 {
return fmt.Errorf("you are using kustomize %q\n"+
"Please update your kustomize version to >= %v\n"+
"See kustomize installation: %v", match[1], kustomizeMinVersion,
kustomizeDownloadLink)
}
}
return nil
}

// Deploy hydrates the manifests using kustomizations and kpt functions as described in the render method,
// outputs them to the applyDir, and runs `kpt live apply` against applyDir to create resources in the cluster.
// `kpt live apply` supports automated pruning declaratively via resources in the applyDir.
func (k *Deployer) Deploy(ctx context.Context, out io.Writer, builds []build.Artifact) ([]string, error) {
if err := sanityCheck(k.Dir); err != nil {
return nil, err
}
flags, err := k.getKptFnRunArgs()
if err != nil {
return []string{}, err
Expand Down Expand Up @@ -166,6 +229,9 @@ func (k *Deployer) Cleanup(ctx context.Context, out io.Writer) error {

// Render hydrates manifests using both kustomization and kpt functions.
func (k *Deployer) Render(ctx context.Context, out io.Writer, builds []build.Artifact, _ bool, filepath string) error {
if err := sanityCheck(k.Dir); err != nil {
return err
}
flags, err := k.getKptFnRunArgs()
if err != nil {
return err
Expand Down
104 changes: 103 additions & 1 deletion pkg/skaffold/deploy/kpt/kpt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ func TestKpt_Deploy(t *testing.T) {
},
}
for _, test := range tests {
sanityCheck = func(dir string) error { return nil }
testutil.Run(t, test.description, func(t *testutil.T) {
t.Override(&util.DefaultExecCommand, test.commands)
tmpDir := t.NewTempDir().Chdir()
Expand All @@ -229,7 +230,6 @@ func TestKpt_Deploy(t *testing.T) {
}

_, err := k.Deploy(context.Background(), ioutil.Discard, test.builds)

t.CheckError(test.shouldErr, err)
})
}
Expand Down Expand Up @@ -1015,6 +1015,108 @@ spec:
}
}

func TestVersionCheck(t *testing.T) {
tests := []struct {
description string
commands util.Command
kustomizations map[string]string
shouldErr bool
error error
}{
{
description: "Both kpt and kustomize versions are good",
commands: testutil.
CmdRunOut("kpt version", `0.34.0`).
AndRunOut("kustomize version", `{Version:v3.6.1 GitCommit:a0072a2cf92bf5399565e84c621e1e7c5c1f1094 BuildDate:2020-06-15T20:19:07Z GoOs:darwin GoArch:amd64}`),
kustomizations: map[string]string{"Kustomization": `resources:
- foo.yaml`},
shouldErr: false,
error: nil,
},
{
description: "kpt is not installed",
commands: testutil.CmdRunOutErr("kpt version", "", errors.New("BUG")),
shouldErr: true,
error: fmt.Errorf("kpt is not installed yet\nSee kpt installation: %v",
kptDownloadLink),
},
{
description: "kustomize is not used, kpt version is good",
commands: testutil.
CmdRunOut("kpt version", `0.34.0`),
shouldErr: false,
error: nil,
},
{
description: "kustomize is used but not installed",
commands: testutil.
CmdRunOut("kpt version", `0.34.0`).
AndRunOutErr("kustomize version", "", errors.New("BUG")),
kustomizations: map[string]string{"Kustomization": `resources:
- foo.yaml`},
shouldErr: true,
error: fmt.Errorf("kustomize is not installed yet\nSee kpt installation: %v",
kustomizeDownloadLink),
},
{
description: "kpt version is too old (<0.34.0)",
commands: testutil.
CmdRunOut("kpt version", `0.1.0`),
kustomizations: map[string]string{"Kustomization": `resources:
- foo.yaml`},
shouldErr: true,
error: fmt.Errorf("you are using kpt \"0.1.0\"\n"+
"Please update your kpt version to >= %v\nSee kpt installation: %v",
kptMinVersion, kptDownloadLink),
},
{
description: "kpt version is unknown",
commands: testutil.
CmdRunOut("kpt version", `unknown`),
kustomizations: map[string]string{"Kustomization": `resources:
- foo.yaml`},
shouldErr: true,
error: fmt.Errorf("unknown kpt version unknown\nPlease upgrade your "+
"local kpt CLI to a version >= %v\nSee kpt installation: %v",
kptMinVersion, kptDownloadLink),
},
{
description: "kustomize versions is too old (< v3.2.3)",
commands: testutil.
CmdRunOut("kpt version", `0.34.0`).
AndRunOut("kustomize version", `{Version:v0.0.1 GitCommit:a0072a2cf92bf5399565e84c621e1e7c5c1f1094 BuildDate:2020-06-15T20:19:07Z GoOs:darwin GoArch:amd64}`),
kustomizations: map[string]string{"Kustomization": `resources:
- foo.yaml`},
shouldErr: true,
error: fmt.Errorf("you are using kustomize \"v0.0.1\"\n"+
"Please update your kustomize version to >= %v\n"+
"See kustomize installation: %v", kustomizeMinVersion, kustomizeDownloadLink),
},
{
description: "kustomize versions is unknown",
commands: testutil.
CmdRunOut("kpt version", `0.34.0`).
AndRunOut("kustomize version", `{Version:unknown GitCommit:a0072a2cf92bf5399565e84c621e1e7c5c1f1094 BuildDate:2020-06-15T20:19:07Z GoOs:darwin GoArch:amd64}`),
kustomizations: map[string]string{"Kustomization": `resources:
- foo.yaml`},
shouldErr: true,
error: fmt.Errorf("unknown kustomize version unknown\nPlease upgrade your "+
"local kustomize CLI to a version >= %v\nSee kustomize installation: %v",
kustomizeMinVersion, kustomizeDownloadLink),
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
t.Override(&util.DefaultExecCommand, test.commands)
tmpDir := t.NewTempDir().Chdir()
tmpDir.WriteFiles(test.kustomizations)
err := versionCheck("")
t.CheckError(test.shouldErr, err)
})
testutil.CheckError(t, test.shouldErr, test.error)
}
}

type kptConfig struct {
runcontext.RunContext // Embedded to provide the default values.
workingDir string
Expand Down
1 change: 1 addition & 0 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ golang.org/x/crypto/ssh/terminal
golang.org/x/lint
golang.org/x/lint/golint
# golang.org/x/mod v0.3.0
## explicit
golang.org/x/mod/module
golang.org/x/mod/semver
# golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2
Expand Down