Skip to content
Open
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
46 changes: 36 additions & 10 deletions pkg/types/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,39 +268,62 @@ func parseLayers(referenceDirectory string, lms yaml.MapSlice, requireHash bool)
// Let's make sure that all the things people supplied in the layers are
// actually things this stacker understands.
for _, e := range lms {
for _, directive := range e.Value.(yaml.MapSlice) {
directives, ok := e.Value.(yaml.MapSlice)
if !ok {
return nil, errors.Errorf("stackerfile: layer '%v' must be a map of directives, found: %#v",
e.Key, e.Value)
}

for _, directive := range directives {
key, ok := directive.Key.(string)
if !ok {
return nil, errors.Errorf("stackerfile: layer '%v': directive %v is not a string",
e.Key, directive.Key)
}

found := false
for _, field := range layerFields {
if directive.Key.(string) == field {
if key == field {
found = true
break
}
}

if !found {
return nil, errors.Errorf("stackerfile: unknown directive %s", directive.Key.(string))
return nil, errors.Errorf("stackerfile: unknown directive %s", key)
}

if directive.Key.(string) == "from" {
for _, sourceDirective := range directive.Value.(yaml.MapSlice) {
if key == "from" {
sourceDirectives, ok := directive.Value.(yaml.MapSlice)
if !ok {
return nil, errors.Errorf("stackerfile: layer '%v': 'from' must be a map with a 'type' "+
"and a 'url' or 'tag', found: %#v", e.Key, directive.Value)
}

for _, sourceDirective := range sourceDirectives {
sourceKey, ok := sourceDirective.Key.(string)
if !ok {
return nil, errors.Errorf("stackerfile: layer '%v': image source directive %v "+
"is not a string", e.Key, sourceDirective.Key)
}

found = false
for _, field := range imageSourceFields {
if sourceDirective.Key.(string) == field {
if sourceKey == field {
found = true
break
}
}

if !found {
return nil, errors.Errorf("stackerfile: unknown image source directive %s",
sourceDirective.Key.(string))
return nil, errors.Errorf("stackerfile: unknown image source directive %s", sourceKey)
}
}
}

if directive.Key.(string) == "os" || directive.Key.(string) == "arch" {
if key == "os" || key == "arch" {
if directive.Value == nil {
return nil, errors.Errorf("stackerfile: %q value cannot be empty", directive.Key.(string))
return nil, errors.Errorf("stackerfile: %q value cannot be empty", key)
}
}
}
Expand Down Expand Up @@ -456,6 +479,9 @@ func getImportFromInterface(v interface{}) (Import, error) {
// if it is a simple string, that is the path
s, ok := v.(string)
if ok {
if s == "" {
return Import{}, errors.Errorf("import path cannot be empty")
}
ret.Path = s
return ret, nil
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/types/layer_import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ func TestGetImportFromInterface(t *testing.T) {
{desc: "relative string",
val: "path/to/file",
expected: Import{Path: "path/to/file", Uid: eUGid, Gid: eUGid}},
{desc: "string cannot be empty",
val: "",
errstr: "import path cannot be empty"},
{desc: "dict no dest",
val: map[interface{}]interface{}{
"path": "/path/to/file",
Expand Down
50 changes: 50 additions & 0 deletions pkg/types/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package types

import (
"os"
"path/filepath"
"reflect"
"strings"
"testing"
)

Expand Down Expand Up @@ -51,6 +53,54 @@ func TestDockerFrom(t *testing.T) {
}
}

func TestMalformedLayers(t *testing.T) {
tables := []struct {
desc string
content string
errstr string
}{
{desc: "layer is a string",
content: "foo: bar\n",
errstr: "must be a map of directives"},
{desc: "layer is empty",
content: "foo:\n",
errstr: "must be a map of directives"},
{desc: "directive is not a string",
content: "foo:\n 1: bar\n",
errstr: "directive 1 is not a string"},
{desc: "from is a string",
content: "foo:\n from: docker://ubuntu:latest\n",
errstr: "'from' must be a map"},
{desc: "from is empty",
content: "foo:\n from:\n",
errstr: "'from' must be a map"},
{desc: "image source directive is not a string",
content: "foo:\n from:\n 1: docker\n",
errstr: "image source directive 1 is not a string"},
{desc: "import path is empty",
content: "foo:\n from:\n type: scratch\n imports:\n - \"\"\n",
errstr: "import path cannot be empty"},
}

for _, tt := range tables {
t.Run(tt.desc, func(t *testing.T) {
path := filepath.Join(t.TempDir(), "stacker.yaml")
if err := os.WriteFile(path, []byte(tt.content), 0644); err != nil {
t.Fatalf("couldn't write stackerfile: %s", err)
}

_, err := NewStackerfile(path, false, nil)
if err == nil {
t.Fatalf("expected an error parsing %q", tt.content)
}

if !strings.Contains(err.Error(), tt.errstr) {
t.Fatalf("expected error containing %q, got %q", tt.errstr, err)
}
})
}
}

func TestDependencyOrder(t *testing.T) {
content := `first:
from:
Expand Down
Loading