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

Better check for valid Kubernetes manifests #3404

Merged
merged 1 commit into from
Dec 19, 2019
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
8 changes: 3 additions & 5 deletions pkg/skaffold/initializer/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -674,11 +674,9 @@ func checkConfigFile(filePath string, force bool, potentialConfigs *[]string) (b
return true, nil
}

if IsSupportedKubernetesFileExtension(filePath) {
if filepath.Base(filePath) != "package.json" { // Not a valid k8s manifest
*potentialConfigs = append(*potentialConfigs, filePath)
return true, nil
}
if kubectl.IsKubernetesManifest(filePath) {
*potentialConfigs = append(*potentialConfigs, filePath)
return true, nil
}

return false, nil
Expand Down
36 changes: 20 additions & 16 deletions pkg/skaffold/initializer/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ func TestPrintAnalyzeJSONNoJib(t *testing.T) {

func TestWalk(t *testing.T) {
emptyFile := ""
validK8sManifest := "apiVersion: v1\nkind: Service\nmetadata:\n name: test\n"

tests := []struct {
description string
filesWithContents map[string]string
Expand All @@ -139,8 +141,9 @@ func TestWalk(t *testing.T) {
{
description: "should return correct k8 configs and build files (backwards compatibility)",
filesWithContents: map[string]string{
"config/test.yaml": emptyFile,
"k8pod.yml": emptyFile,
"config/test.yaml": validK8sManifest,
"config/invalid.yaml": emptyFile,
"k8pod.yml": validK8sManifest,
"README": emptyFile,
"deploy/Dockerfile": emptyFile,
"gradle/build.gradle": emptyFile,
Expand All @@ -161,8 +164,9 @@ func TestWalk(t *testing.T) {
{
description: "should return correct k8 configs and build files",
filesWithContents: map[string]string{
"config/test.yaml": emptyFile,
"k8pod.yml": emptyFile,
"config/test.yaml": validK8sManifest,
"config/invalid.yaml": emptyFile,
"k8pod.yml": validK8sManifest,
"README": emptyFile,
"deploy/Dockerfile": emptyFile,
"gradle/build.gradle": emptyFile,
Expand All @@ -189,8 +193,8 @@ func TestWalk(t *testing.T) {
{
description: "skip validating nested jib configs",
filesWithContents: map[string]string{
"config/test.yaml": emptyFile,
"k8pod.yml": emptyFile,
"config/test.yaml": validK8sManifest,
"k8pod.yml": validK8sManifest,
"gradle/build.gradle": emptyFile,
"gradle/subproject/build.gradle": emptyFile,
"maven/asubproject/pom.xml": emptyFile,
Expand All @@ -213,9 +217,9 @@ func TestWalk(t *testing.T) {
filesWithContents: map[string]string{
"build.gradle": emptyFile,
"ignored-builder/build.gradle": emptyFile,
"not-ignored-config/test.yaml": emptyFile,
"not-ignored-config/test.yaml": validK8sManifest,
"Dockerfile": emptyFile,
"k8pod.yml": emptyFile,
"k8pod.yml": validK8sManifest,
"pom.xml": emptyFile,
},
force: false,
Expand All @@ -234,8 +238,8 @@ func TestWalk(t *testing.T) {
{
description: "should skip hidden dir",
filesWithContents: map[string]string{
".hidden/test.yaml": emptyFile,
"k8pod.yml": emptyFile,
".hidden/test.yaml": validK8sManifest,
"k8pod.yml": validK8sManifest,
"README": emptyFile,
".hidden/Dockerfile": emptyFile,
"Dockerfile": emptyFile,
Expand All @@ -257,8 +261,8 @@ func TestWalk(t *testing.T) {
kind: Config
deploy:
kustomize: {}`,
"config/test.yaml": emptyFile,
"k8pod.yml": emptyFile,
"config/test.yaml": validK8sManifest,
"k8pod.yml": validK8sManifest,
"README": emptyFile,
"deploy/Dockerfile": emptyFile,
"Dockerfile": emptyFile,
Expand All @@ -278,8 +282,8 @@ deploy:
{
description: "should error when skaffold.config present and force = false",
filesWithContents: map[string]string{
"config/test.yaml": emptyFile,
"k8pod.yml": emptyFile,
"config/test.yaml": validK8sManifest,
"k8pod.yml": validK8sManifest,
"README": emptyFile,
"deploy/Dockerfile": emptyFile,
"Dockerfile": emptyFile,
Expand All @@ -297,8 +301,8 @@ deploy:
{
description: "should error when skaffold.config present with jib config",
filesWithContents: map[string]string{
"config/test.yaml": emptyFile,
"k8pod.yml": emptyFile,
"config/test.yaml": validK8sManifest,
"k8pod.yml": validK8sManifest,
"README": emptyFile,
"pom.xml": emptyFile,
"skaffold.yaml": `apiVersion: skaffold/v1beta6
Expand Down
14 changes: 11 additions & 3 deletions pkg/skaffold/initializer/kubectl/kubectl.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ import (
k8syaml "k8s.io/apimachinery/pkg/util/yaml"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
)

// ValidSuffixes are the supported file formats for Kubernetes manifests
var ValidSuffixes = []string{".yml", ".yaml", ".json"}

var requiredFields = []string{"apiVersion", "kind", "metadata"}

// Kubectl holds parameters to run kubectl.
Expand Down Expand Up @@ -62,6 +60,16 @@ func New(potentialConfigs []string) (*Kubectl, error) {
}, nil
}

// IsKubernetesManifest is for determining if a file is a valid Kubernetes manifest
func IsKubernetesManifest(file string) bool {
if !util.IsSupportedKubernetesFormat(file) {
return false
}

_, err := parseImagesFromKubernetesYaml(file)
return err == nil
}

// GenerateDeployConfig implements the Initializer interface and generates
// skaffold kubectl deployment config.
func (k *Kubectl) GenerateDeployConfig() latest.DeployConfig {
Expand Down
61 changes: 61 additions & 0 deletions pkg/skaffold/initializer/kubectl/kubectl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,64 @@ spec:
})
}
}

func TestIsKubernetesManifest(t *testing.T) {
tests := []struct {
description string
filename string
content string
expected bool
}{
{
description: "valid k8 yaml filename format",
filename: "test1.yaml",
content: "apiVersion: v1\nkind: Service\nmetadata:\n name: test\n",
expected: true,
},
{
description: "valid k8 json filename format",
filename: "test1.json",
content: `{"apiVersion":"v1","kind":"Service","metadata":{"name": "test"}}`,
expected: true,
},
{
description: "valid k8 yaml filename format",
filename: "test1.yml",
content: "apiVersion: v1\nkind: Service\nmetadata:\n name: test\n",
expected: true,
},
{
description: "invalid k8 yaml",
filename: "test1.yaml",
content: "key: value",
expected: false,
},
{
description: "invalid k8 json",
filename: "test1.json",
content: `{}`,
expected: false,
},
{
description: "invalid k8s yml",
filename: "test1.yml",
content: "key: value",
expected: false,
},
{
description: "invalid file",
filename: "some.config",
content: "",
expected: false,
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
t.NewTempDir().Write(test.filename, test.content).Chdir()

supported := IsKubernetesManifest(test.filename)

t.CheckDeepEqual(test.expected, supported)
})
}
}
19 changes: 1 addition & 18 deletions pkg/skaffold/initializer/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,7 @@ limitations under the License.

package initializer

import (
"strings"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/kubectl"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema"
)

// IsSupportedKubernetesFileExtension is for determining if a file under a glob pattern
// is deployable file format. It makes no attempt to check whether or not the file
// is actually deployable or has the correct contents.
func IsSupportedKubernetesFileExtension(n string) bool {
for _, s := range kubectl.ValidSuffixes {
if strings.HasSuffix(n, s) {
return true
}
}
return false
}
import "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema"

// IsSkaffoldConfig is for determining if a file is skaffold config file.
func IsSkaffoldConfig(file string) bool {
Expand Down
36 changes: 0 additions & 36 deletions pkg/skaffold/initializer/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,6 @@ import (
"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestIsSupportedKubernetesFileExtension(t *testing.T) {
tests := []struct {
description string
filename string
expected bool
}{
{
description: "valid k8 yaml filename format",
filename: "test1.yaml",
expected: true,
},
{
description: "valid k8 json filename format",
filename: "test1.json",
expected: true,
},
{
description: "valid k8 yaml filename format",
filename: "test1.yml",
expected: true,
},
{
description: "invalid file",
filename: "some.config",
expected: false,
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
supported := IsSupportedKubernetesFileExtension(test.filename)

t.CheckDeepEqual(test.expected, supported)
})
}
}

func TestIsSkaffoldConfig(t *testing.T) {
tests := []struct {
description string
Expand Down