Skip to content
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
65 changes: 65 additions & 0 deletions test/binds.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
load helpers

function setup() {
stacker_setup
}

function teardown() {
cleanup
}

@test "bind as string slice" {
cat > stacker.yaml <<"EOF"
bind-test:
from:
type: oci
url: ${{CENTOS_OCI}}
binds:
- ${{bind_path}} -> /root/tree1/foo
run: |
touch /root/tree1/foo/bar
EOF
mkdir -p tree1/foo

# since we are creating directory as
# real root and then `touch`-ing a file
# where in user NS, need to have rw persmission
# for others
chmod +666 tree1/foo

bind_path=$(realpath tree1/foo)

out=$(stacker build --substitute bind_path=${bind_path} --substitute CENTOS_OCI=$CENTOS_OCI)

[[ "${out}" =~ ^(.*filesystem bind-test built successfully)$ ]]

stat tree1/foo/bar
}

@test "bind as struct" {
cat > stacker.yaml <<"EOF"
bind-test:
from:
type: oci
url: ${{CENTOS_OCI}}
binds:
- Source: ${{bind_path}}
Dest: /root/tree1/foo
run: |
touch /root/tree1/foo/bar
EOF
mkdir -p tree1/foo

# since we are creating directory as
# real root and then `touch`-ing a file
# where in user NS, need to have rw persmission
# for others
chmod +666 tree1/foo

bind_path=$(realpath tree1/foo)

out=$(stacker build --substitute bind_path=$bind_path --substitute CENTOS_OCI=$CENTOS_OCI)
[[ "${out}" =~ ^(.*filesystem bind-test built successfully)$ ]]

stat tree1/foo/bar
}
61 changes: 53 additions & 8 deletions types/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,67 @@ type OverlayDir struct {

type Imports []Import

func getStringOrStringSlice(iface interface{}, xform func(string) ([]string, error)) ([]string, error) {
func validateDataAsBind(i interface{}) (map[interface{}]interface{}, error) {
bindMap, ok := i.(map[interface{}]interface{})
if !ok {
return nil, errors.Errorf("unable to cast into map[interface{}]interface{}: %T", i)
}

// validations
bindSource, ok := bindMap["Source"]
if !ok {
return nil, errors.Errorf("bind source missing: %v", i)
}

_, ok = bindSource.(string)
if !ok {
return nil, errors.Errorf("unknown bind source type, expected string: %T", i)
}

bindDest, ok := bindMap["Dest"]
if !ok {
return nil, errors.Errorf("bind dest missing: %v", i)
}

_, ok = bindDest.(string)
if !ok {
return nil, errors.Errorf("unknown bind dest type, expected string: %T", i)
}

if bindSource == "" || bindDest == "" {
return nil, errors.Errorf("empty source or dest: %v", i)
}

return bindMap, nil
}

func getStringOrStringSlice(data interface{}, xform func(string) ([]string, error)) ([]string, error) {
// The user didn't supply run: at all, so let's not do anything.
if iface == nil {
if data == nil {
return []string{}, nil
}

// This is how the yaml decoder decodes it if it's:
// run:
// - foo
// - bar
ifs, ok := iface.([]interface{})
ifs, ok := data.([]interface{})
if ok {
strs := []string{}
for _, i := range ifs {
s, ok := i.(string)
if !ok {
s := ""
switch v := i.(type) {
case string:
s = v
case interface{}:
bindMap, err := validateDataAsBind(i)
if err != nil {
return nil, err
}

// validations passed, return as string in form: source -> dest
s = fmt.Sprintf("%s -> %s", bindMap["Source"], bindMap["Dest"])
default:
return nil, errors.Errorf("unknown run array type: %T", i)
}

Expand All @@ -72,20 +117,20 @@ func getStringOrStringSlice(iface interface{}, xform func(string) ([]string, err
// run: |
// echo hello world
// echo goodbye cruel world
line, ok := iface.(string)
line, ok := data.(string)
if ok {
return xform(line)
}

// This is how it is after we do our find replace and re-set it; as a
// convenience (so we don't have to re-wrap it in interface{}), let's
// handle []string
strs, ok := iface.([]string)
strs, ok := data.([]string)
if ok {
return strs, nil
}

return nil, errors.Errorf("unknown directive type: %T", iface)
return nil, errors.Errorf("unknown directive type: %T", data)
}

// StringList allows this type to be parsed from the yaml parser as either a
Expand Down