mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Assert keeps going after failure, but require immediately fails the tests, making it easier to find the output related to the test failure, rather than having to comb through a bunch of subsequent assertion failures. For equality tests, we may or may not want to continue, but for error checks we almost always want to immediately fail the test. Exceptions can be changed as-needed.
459 lines
10 KiB
Go
459 lines
10 KiB
Go
// Copyright 2022 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package krusty_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
|
"sigs.k8s.io/kustomize/api/krusty"
|
|
"sigs.k8s.io/kustomize/api/resmap"
|
|
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
)
|
|
|
|
func TestRemoteLoad_LocalProtocol(t *testing.T) {
|
|
type testRepos struct {
|
|
root string
|
|
simple string
|
|
noSuffix string
|
|
hash string
|
|
multiBaseDev string
|
|
withSubmodule string
|
|
}
|
|
|
|
// creates git repos under a root temporary directory with the following structure
|
|
// root/
|
|
// simple.git/ - base with just a pod
|
|
// nosuffix/ - same as simple.git/ without the .git suffix
|
|
// hash-xx/ - same as simple.git/ with random hash at xx
|
|
// multibase.git/ - base with a dev overlay
|
|
// with-submodule.git/ - includes `simple` as a submodule
|
|
// submodule/ - the submodule referencing `simple`
|
|
createGitRepos := func(t *testing.T) testRepos {
|
|
t.Helper()
|
|
|
|
bash := func(script string) {
|
|
cmd := exec.Command("sh", "-c", script)
|
|
o, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("error running %v\nerr: %v\n%s", script, err, string(o))
|
|
}
|
|
}
|
|
root := t.TempDir()
|
|
|
|
hashPath, err := os.MkdirTemp(root, "hash-")
|
|
require.NoError(t, err)
|
|
hashDir := filepath.Base(hashPath)
|
|
|
|
bash(fmt.Sprintf(`
|
|
set -eux
|
|
|
|
export ROOT="%s"
|
|
export HASH_DIR="%s"
|
|
export GIT_AUTHOR_EMAIL=nobody@kustomize.io
|
|
export GIT_AUTHOR_NAME=Nobody
|
|
export GIT_COMMITTER_EMAIL=nobody@kustomize.io
|
|
export GIT_COMMITTER_NAME=Nobody
|
|
|
|
cp -r testdata/remoteload/simple $ROOT/simple.git
|
|
(
|
|
cd $ROOT/simple.git
|
|
git config --global protocol.file.allow always
|
|
git init --initial-branch=main
|
|
git add .
|
|
git commit -m "import"
|
|
git checkout -b change-image
|
|
cat >>kustomization.yaml <<EOF
|
|
|
|
images:
|
|
- name: nginx
|
|
newName: nginx
|
|
newTag: "2"
|
|
EOF
|
|
git commit -am "image change"
|
|
git checkout main
|
|
)
|
|
cp -r $ROOT/simple.git $ROOT/nosuffix
|
|
cp -r testdata/remoteload/multibase $ROOT/multibase.git
|
|
(
|
|
cd $ROOT/multibase.git
|
|
git init --initial-branch=main
|
|
git add .
|
|
git commit -m "import"
|
|
)
|
|
cp -r testdata/remoteload/with-submodule $ROOT/with-submodule.git # see README
|
|
cp -r $ROOT/simple.git/. $ROOT/$HASH_DIR
|
|
(
|
|
cd $ROOT/with-submodule.git
|
|
git init --initial-branch=main
|
|
git add .
|
|
git commit -m "import"
|
|
git checkout -b relative-submodule
|
|
git submodule add ../$HASH_DIR submodule
|
|
git commit -m "relative submodule"
|
|
git checkout main
|
|
git submodule add $ROOT/simple.git submodule
|
|
git commit -m "submodule"
|
|
)
|
|
`, root, hashDir))
|
|
return testRepos{
|
|
root: root,
|
|
// The strings below aren't currently used, and more serve as documentation.
|
|
simple: "simple.git",
|
|
noSuffix: "nosuffix",
|
|
hash: hashDir,
|
|
multiBaseDev: "multibase.git",
|
|
withSubmodule: "with-submodule.git",
|
|
}
|
|
}
|
|
|
|
const simpleBuild = `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
labels:
|
|
app: myapp
|
|
name: myapp-pod
|
|
spec:
|
|
containers:
|
|
- image: nginx:1.7.9
|
|
name: nginx
|
|
`
|
|
var simpleBuildWithNginx2 = strings.ReplaceAll(simpleBuild, "nginx:1.7.9", "nginx:2")
|
|
var multibaseDevExampleBuild = strings.ReplaceAll(simpleBuild, "myapp-pod", "dev-myapp-pod")
|
|
|
|
repos := createGitRepos(t)
|
|
tests := []struct {
|
|
name string
|
|
kustomization string
|
|
expected string
|
|
err string
|
|
skip bool
|
|
}{
|
|
{
|
|
name: "simple",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/simple.git
|
|
`,
|
|
expected: simpleBuild,
|
|
},
|
|
{
|
|
name: "without git suffix",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/nosuffix
|
|
`,
|
|
expected: simpleBuild,
|
|
},
|
|
{
|
|
name: "has path",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/multibase.git/dev
|
|
`,
|
|
expected: multibaseDevExampleBuild,
|
|
},
|
|
{
|
|
name: "has path without git suffix",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/multibase//dev
|
|
`,
|
|
expected: multibaseDevExampleBuild,
|
|
},
|
|
{
|
|
name: "has ref",
|
|
kustomization: `
|
|
resources:
|
|
- "file://$ROOT/simple.git?ref=change-image"
|
|
`,
|
|
|
|
expected: simpleBuildWithNginx2,
|
|
},
|
|
{
|
|
// Version is the same as ref
|
|
name: "has version",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/simple.git?version=change-image
|
|
`,
|
|
expected: simpleBuildWithNginx2,
|
|
},
|
|
{
|
|
name: "has submodule",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/with-submodule.git/submodule
|
|
`,
|
|
expected: simpleBuild,
|
|
},
|
|
{
|
|
name: "has relative submodule",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/with-submodule.git/submodule?ref=relative-submodule
|
|
`,
|
|
|
|
expected: simpleBuild,
|
|
},
|
|
{
|
|
name: "has timeout",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/simple.git?timeout=500
|
|
`,
|
|
expected: simpleBuild,
|
|
},
|
|
{
|
|
name: "has submodule but not initialized",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/with-submodule.git/submodule?submodules=0
|
|
`,
|
|
err: "unable to find one of 'kustomization.yaml', 'kustomization.yml' or 'Kustomization' in directory",
|
|
},
|
|
{
|
|
name: "has origin annotation",
|
|
skip: true, // The annotated path should be "pod.yaml" but is "notCloned/pod.yaml"
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/simple.git
|
|
buildMetadata: [originAnnotations]
|
|
`,
|
|
expected: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
annotations:
|
|
config.kubernetes.io/origin: |
|
|
path: pod.yaml
|
|
repo: file://$ROOT/simple.git
|
|
labels:
|
|
app: myapp
|
|
name: myapp-pod
|
|
spec:
|
|
containers:
|
|
- image: nginx:1.7.9
|
|
name: nginx
|
|
`,
|
|
},
|
|
{
|
|
name: "has ref path timeout and origin annotation",
|
|
kustomization: `
|
|
resources:
|
|
- file://$ROOT/multibase.git/dev?version=main&timeout=500
|
|
buildMetadata: [originAnnotations]
|
|
`,
|
|
expected: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
annotations:
|
|
config.kubernetes.io/origin: |
|
|
path: base/pod.yaml
|
|
repo: file://$ROOT/multibase.git
|
|
ref: main
|
|
labels:
|
|
app: myapp
|
|
name: dev-myapp-pod
|
|
spec:
|
|
containers:
|
|
- image: nginx:1.7.9
|
|
name: nginx
|
|
`,
|
|
},
|
|
{
|
|
name: "repo does not exist ",
|
|
kustomization: `
|
|
resources:
|
|
- file:///not/a/real/repo
|
|
`,
|
|
err: "fatal: '/not/a/real/repo' does not appear to be a git repository",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if test.skip {
|
|
t.SkipNow()
|
|
}
|
|
|
|
kust := strings.ReplaceAll(test.kustomization, "$ROOT", repos.root)
|
|
fSys, tmpDir := kusttest_test.CreateKustDir(t, kust)
|
|
|
|
b := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
|
|
m, err := b.Run(
|
|
fSys,
|
|
tmpDir.String())
|
|
|
|
if test.err != "" {
|
|
require.Error(t, err)
|
|
require.Regexp(t, test.err, err.Error())
|
|
} else {
|
|
require.NoError(t, err)
|
|
checkYaml(t, m, strings.ReplaceAll(test.expected, "$ROOT", repos.root))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemoteLoad_RemoteProtocols(t *testing.T) {
|
|
// Slow remote tests with long timeouts.
|
|
// TODO: If these end up flaking, they should retry. If not, remove this TODO.
|
|
tests := []struct {
|
|
name string
|
|
kustomization string
|
|
err string
|
|
errT error
|
|
beforeTest func(t *testing.T)
|
|
}{
|
|
{
|
|
name: "https",
|
|
kustomization: `
|
|
resources:
|
|
- https://github.com/kubernetes-sigs/kustomize//examples/multibases/dev/?submodules=0&ref=kustomize%2Fv4.5.7&timeout=300
|
|
`,
|
|
},
|
|
{
|
|
name: "https with explicit .git suffix",
|
|
kustomization: `
|
|
resources:
|
|
- https://github.com/kubernetes-sigs/kustomize.git//examples/multibases/dev/?submodules=0&ref=kustomize%2Fv4.5.7&timeout=300
|
|
`,
|
|
},
|
|
{
|
|
name: "git double-colon https",
|
|
kustomization: `
|
|
resources:
|
|
- git::https://github.com/kubernetes-sigs/kustomize//examples/multibases/dev/?submodules=0&ref=kustomize%2Fv4.5.7&timeout=300
|
|
`,
|
|
},
|
|
{
|
|
name: "https raw remote file",
|
|
kustomization: `
|
|
resources:
|
|
- https://raw.githubusercontent.com/kubernetes-sigs/kustomize/v3.1.0/examples/multibases/base/pod.yaml?timeout=300
|
|
namePrefix: dev-
|
|
`,
|
|
},
|
|
{
|
|
name: "https without scheme",
|
|
kustomization: `
|
|
resources:
|
|
- github.com/kubernetes-sigs/kustomize/examples/multibases/dev?submodules=0&ref=kustomize%2Fv4.5.7&timeout=300
|
|
`,
|
|
},
|
|
{
|
|
name: "ssh",
|
|
beforeTest: configureGitSSHCommand,
|
|
kustomization: `
|
|
resources:
|
|
- git@github.com/kubernetes-sigs/kustomize/examples/multibases/dev?submodules=0&ref=kustomize%2Fv4.5.7&timeout=300
|
|
`,
|
|
},
|
|
{
|
|
name: "ssh with colon",
|
|
beforeTest: configureGitSSHCommand,
|
|
kustomization: `
|
|
resources:
|
|
- git@github.com:kubernetes-sigs/kustomize/examples/multibases/dev?submodules=0&ref=kustomize%2Fv4.5.7&timeout=300
|
|
`,
|
|
},
|
|
{
|
|
name: "ssh scheme",
|
|
beforeTest: configureGitSSHCommand,
|
|
kustomization: `
|
|
resources:
|
|
- ssh://git@github.com/kubernetes-sigs/kustomize/examples/multibases/dev?submodules=0&ref=kustomize%2Fv4.5.7&timeout=300
|
|
`,
|
|
},
|
|
{
|
|
name: "http error",
|
|
kustomization: `
|
|
resources:
|
|
- https://github.com/thisisa404.yaml
|
|
`,
|
|
err: "accumulating resources: accumulating resources from 'https://github.com/thisisa404.yaml': HTTP Error: status code 404 (Not Found)",
|
|
errT: loader.ErrHTTP,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if test.beforeTest != nil {
|
|
test.beforeTest(t)
|
|
}
|
|
fSys, tmpDir := kusttest_test.CreateKustDir(t, test.kustomization)
|
|
|
|
b := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
|
|
m, err := b.Run(
|
|
fSys,
|
|
tmpDir.String())
|
|
|
|
if test.err != "" {
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), test.err)
|
|
if test.errT != nil {
|
|
require.ErrorIs(t, err, test.errT)
|
|
}
|
|
} else {
|
|
require.NoError(t, err)
|
|
const multibaseDevExampleBuild = `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
labels:
|
|
app: myapp
|
|
name: dev-myapp-pod
|
|
spec:
|
|
containers:
|
|
- image: nginx:1.7.9
|
|
name: nginx
|
|
`
|
|
checkYaml(t, m, multibaseDevExampleBuild)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func configureGitSSHCommand(t *testing.T) {
|
|
t.Helper()
|
|
|
|
// This contains a read-only Deploy Key for the kustomize repo.
|
|
node, err := yaml.ReadFile("testdata/repo_read_only_ssh_key.yaml")
|
|
require.NoError(t, err)
|
|
keyB64, err := node.GetString("key")
|
|
require.NoError(t, err)
|
|
key, err := base64.StdEncoding.DecodeString(keyB64)
|
|
require.NoError(t, err)
|
|
|
|
// Write the key to a temp file and use it in SSH
|
|
f, err := os.CreateTemp("", "kustomize_ssh")
|
|
require.NoError(t, err)
|
|
_, err = io.Copy(f, bytes.NewReader(key))
|
|
require.NoError(t, err)
|
|
cmd := fmt.Sprintf("ssh -i %s -o IdentitiesOnly=yes", f.Name())
|
|
const SSHCommandKey = "GIT_SSH_COMMAND"
|
|
t.Setenv(SSHCommandKey, cmd)
|
|
t.Cleanup(func() {
|
|
_ = os.Remove(f.Name())
|
|
})
|
|
}
|
|
|
|
func checkYaml(t *testing.T, actual resmap.ResMap, expected string) {
|
|
t.Helper()
|
|
|
|
yml, err := actual.AsYaml()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, expected, string(yml))
|
|
}
|