From 15c6bef6a54fcb9964ce90aff921c16f0decb90a Mon Sep 17 00:00:00 2001 From: Jordan Sissel Date: Tue, 12 Feb 2019 10:05:20 -0800 Subject: [PATCH] Try a bit harder to provide a clear error message. When an unexpected file format is provided for a chart archive, spend some extra effort to provide the user with some meaningful feedback. This is intended to help users who mistakenly invoke `helm template` like this: helm template values.yaml charts/mychart This is a user error, and now we can report that the argument `values.yaml` was expected to be a chart. Fixes #5296 Signed-off-by: Jordan Sissel --- pkg/chartutil/load.go | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/pkg/chartutil/load.go b/pkg/chartutil/load.go index b0927a5cf..8d96203be 100644 --- a/pkg/chartutil/load.go +++ b/pkg/chartutil/load.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "io/ioutil" + "net/http" "os" "path" "path/filepath" @@ -255,7 +256,45 @@ func LoadFile(name string) (*chart.Chart, error) { } defer raw.Close() - return LoadArchive(raw) + err = ensureArchive(name, raw) + if err != nil { + return nil, err + } + + c, err := LoadArchive(raw) + if err != nil { + if err == gzip.ErrHeader { + return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %s)", name, err) + } + } + return c, err +} + +// ensureArchive's job is to return an informative error if the file does not appear to be a gzipped archive. +// +// Sometimes users will provide a values.yaml for an argument where a chart is expected. One common occurrence +// of this is invoking `helm template values.yaml mychart` which would otherwise produce a confusing error +// if we didn't check for this. +func ensureArchive(name string, raw *os.File) error { + defer raw.Seek(0, 0) // reset read offset to allow archive loading to proceed. + + // Check the file format to give us a chance to provide the user with more actionable feedback. + buffer := make([]byte, 512) + _, err := raw.Read(buffer) + if err != nil && err != io.EOF { + return fmt.Errorf("file '%s' cannot be read: %s", name, err) + } + if contentType := http.DetectContentType(buffer); contentType != "application/x-gzip" { + // TODO: Is there a way to reliably test if a file content is YAML? ghodss/yaml accepts a wide + // variety of content (Makefile, .zshrc) as valid YAML without errors. + + // Wrong content type. Let's check if it's yaml and give an extra hint? + if strings.HasSuffix(name, ".yml") || strings.HasSuffix(name, ".yaml") { + return fmt.Errorf("file '%s' seems to be a YAML file, but I expected a gzipped archive", name) + } + return fmt.Errorf("file '%s' does not appear to be a gzipped archive; got '%s'", name, contentType) + } + return nil } // LoadDir loads from a directory.