Skip to content

Commit

Permalink
Add --vars-inline that is capable of overwriting --vars
Browse files Browse the repository at this point in the history
  • Loading branch information
pedroMMM committed Jan 2, 2020
1 parent 16c3099 commit e9e37b0
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 26 deletions.
6 changes: 5 additions & 1 deletion cmd/goss/goss.go
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/aelsabbahy/goss"
"github.com/aelsabbahy/goss/outputs"
"github.com/urfave/cli"
//"time"
)

var version string
Expand All @@ -33,6 +32,11 @@ func main() {
Usage: "json/yaml file containing variables for template",
EnvVar: "GOSS_VARS",
},
cli.StringFlag{
Name: "vars-inline",
Usage: "json/yaml string containing variables for template (overwrites vars)",
EnvVar: "GOSS_VARS-INLINE",
},
cli.StringFlag{
Name: "package",
Usage: "Package type to use [rpm, deb, apk, pacman]",
Expand Down
25 changes: 12 additions & 13 deletions docs/manual.md
Expand Up @@ -47,21 +47,20 @@ VERSION:
0.0.0
COMMANDS:
validate, v Validate system
serve, s Serve a health endpoint
render, r render gossfile after imports
autoadd, aa automatically add all matching resource to the test suite
add, a add a resource to the test suite
help, h Shows a list of commands or help for one command
validate, v Validate system
serve, s Serve a health endpoint
render, r render gossfile after imports
autoadd, aa automatically add all matching resource to the test suite
add, a add a resource to the test suite
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--gossfile, -g "./goss.yaml" Goss file to read from / write to [$GOSS_FILE]
--vars value json/yaml file containing variables for template [$GOSS_VARS]
--package Package type to use [rpm, deb, apk, pacman]
--help, -h show help
--generate-bash-completion
--version, -v print the version
--gossfile value, -g value Goss file to read from / write to (default: "./goss.yaml") [$GOSS_FILE]
--vars value json/yaml file containing variables for template [$GOSS_VARS]
--vars-inline value json/yaml string containing variables for template (overwrites vars) [$GOSS_VARS-INLINE]
--package value Package type to use [rpm, deb, apk, pacman]
--help, -h show help
--version, -v print the version
```
**Note:** *Most flags can be set by using environment variables, see `--help` for more info.*

Expand Down
8 changes: 8 additions & 0 deletions integration-tests/goss/goss-shared.yaml
Expand Up @@ -229,3 +229,11 @@ matching:
matches:
not:
semver-constraint: ">1.0.0 <2.0.0 !=1.5.0"
vars_inline_simple:
content: {{ .Vars.inline }}
matches:
match-regexp: bar
vars_inline_overwrite:
content: {{ .Vars.overwrite }}
matches:
match-regexp: bar
2 changes: 2 additions & 0 deletions integration-tests/goss/vars.yaml
Expand Up @@ -13,3 +13,5 @@ precise:
wheezy:
packages:
apache2: "2.2.22-13+deb7u13"

overwrite: foo
7 changes: 4 additions & 3 deletions integration-tests/test.sh
Expand Up @@ -4,6 +4,7 @@ set -xeu

os=$1
arch=$2
vars_inline="{inline: bar, overwrite: bar}"

seccomp_opts() {
local docker_ver minor_ver
Expand Down Expand Up @@ -40,13 +41,13 @@ trap "rv=\$?; docker rm -vf $id; exit \$rv" INT TERM EXIT
[[ $os != "arch" ]] && docker_exec "/goss/$os/goss-linux-$arch" -g "/goss/goss-wait.yaml" validate -r 10s -s 100ms && sleep 1

#out=$(docker exec "$container_name" bash -c "time /goss/$os/goss-linux-$arch -g /goss/$os/goss.yaml validate")
out=$(docker_exec "/goss/$os/goss-linux-$arch" --vars "/goss/vars.yaml" -g "/goss/$os/goss.yaml" validate)
out=$(docker_exec "/goss/$os/goss-linux-$arch" --vars "/goss/vars.yaml" --vars-inline "$vars_inline" -g "/goss/$os/goss.yaml" validate)
echo "$out"

if [[ $os == "arch" ]]; then
egrep -q 'Count: 84, Failed: 0, Skipped: 3' <<<"$out"
egrep -q 'Count: 86, Failed: 0, Skipped: 3' <<<"$out"
else
egrep -q 'Count: 101, Failed: 0, Skipped: 5' <<<"$out"
egrep -q 'Count: 103, Failed: 0, Skipped: 5' <<<"$out"
fi

if [[ ! $os == "arch" ]]; then
Expand Down
24 changes: 19 additions & 5 deletions store.go
Expand Up @@ -52,7 +52,7 @@ func getStoreFormatFromData(data []byte) int {
return 0
}

// Reads json file returning GossConfig
// ReadJSON Reads json file returning GossConfig
func ReadJSON(filePath string) GossConfig {
file, err := ioutil.ReadFile(filePath)
if err != nil {
Expand Down Expand Up @@ -92,7 +92,20 @@ func varsFromFile(varsFile string) (map[string]interface{}, error) {
return vars, nil
}

// Reads json byte array returning GossConfig
func varsFromString(varsString string) (map[string]interface{}, error) {
var vars map[string]interface{}
if varsString == "" {
return vars, nil
}
data := []byte(varsString)
format := getStoreFormatFromData(data)
if err := unmarshal(data, &vars, format); err != nil {
return vars, err
}
return vars, nil
}

// ReadJSONData Reads json byte array returning GossConfig
func ReadJSONData(data []byte, detectFormat bool) GossConfig {
if TemplateFilter != nil {
data = TemplateFilter(data)
Expand All @@ -115,12 +128,13 @@ func ReadJSONData(data []byte, detectFormat bool) GossConfig {
return *gossConfig
}

// Reads json file recursively returning string
// RenderJSON Reads json file recursively returning string
func RenderJSON(c *cli.Context) string {
filePath := c.GlobalString("gossfile")
varsFile := c.GlobalString("vars")
varsInline := c.GlobalString("vars-inline")
debug = c.Bool("debug")
TemplateFilter = NewTemplateFilter(varsFile)
TemplateFilter = NewTemplateFilter(varsFile, varsInline)
path := filepath.Dir(filePath)
OutStoreFormat = getStoreFormatFromFileName(filePath)
gossConfig := mergeJSONData(ReadJSON(filePath), 0, path)
Expand All @@ -144,7 +158,7 @@ func mergeJSONData(gossConfig GossConfig, depth int, path string) GossConfig {

// Sort the gossfiles to ensure consistent ordering
var keys []string
for k, _ := range gossConfig.Gossfiles {
for k := range gossConfig.Gossfiles {
keys = append(keys, k)
}
sort.Strings(keys)
Expand Down
121 changes: 121 additions & 0 deletions store_test.go
@@ -0,0 +1,121 @@
package goss

import (
"testing"

"github.com/stretchr/testify/assert"
)

func Test_varsFromString(t *testing.T) {
tests := []struct {
name string
arg string
want map[string]interface{}
wantErr bool
}{
{
name: "empty_string",
arg: ``,
want: nil,
wantErr: false,
},
{
name: "empty_JSON",
arg: `{}`,
want: map[string]interface{}{},
wantErr: false,
},
{
name: "JSON_simple",
arg: `{"a": "a", "b": 1}`,
want: map[string]interface{}{
"a": "a",
"b": float64(1),
},
wantErr: false,
},
{
name: "YAML_simple",
arg: `{a: a, b: 1}`,
want: map[string]interface{}{
"a": "a",
"b": 1,
},
wantErr: false,
},
{
name: "JSON_float",
arg: `{"f": 1.23}`,
want: map[string]interface{}{
"f": 1.23,
},
wantErr: false,
},
{
name: "YAML_float",
arg: `{f: 1.23}`,
want: map[string]interface{}{
"f": 1.23,
},
wantErr: false,
},
{
name: "JSON_list",
arg: `{"l": ["l1", "l2", 3]}`,
want: map[string]interface{}{
"l": []interface{}{
"l1",
"l2",
float64(3),
},
},
wantErr: false,
},
{
name: "YAML_list",
arg: `{l: [l1, l2, 3]}`,
want: map[string]interface{}{
"l": []interface{}{
"l1",
"l2",
3,
},
},
wantErr: false,
},
{
name: "JSON_object",
arg: `{"o": {"oa": "a", "oo": { "oo1": 1 } } }`,
want: map[string]interface{}{
"o": map[string]interface{}{
"oa": "a",
"oo": map[string]interface{}{
"oo1": float64(1),
},
},
},
wantErr: false,
},
{
name: "YAML_object",
arg: `{o: {oa: a, oo: { oo1: 1 } } }`,
want: map[string]interface{}{
"o": map[interface{}]interface{}{
"oa": "a",
"oo": map[interface{}]interface{}{
"oo1": 1,
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := varsFromString(tt.arg)

assert.Equal(t, tt.want, got, "map contents")
assert.Equal(t, tt.wantErr, err != nil, "has error")
})
}
}
17 changes: 14 additions & 3 deletions template.go
Expand Up @@ -42,7 +42,7 @@ func regexMatch(re, s string) (bool, error) {
return compiled.MatchString(s), nil
}

var funcMap = map[string]interface{}{
var funcMap = template.FuncMap{
"mkSlice": mkSlice,
"readFile": readFile,
"getEnv": getEnv,
Expand All @@ -51,17 +51,28 @@ var funcMap = map[string]interface{}{
"toLower": strings.ToLower,
}

func NewTemplateFilter(varsFile string) func([]byte) []byte {
func NewTemplateFilter(varsFile string, varsInline string) func([]byte) []byte {
vars, err := varsFromFile(varsFile)
if err != nil {
fmt.Printf("Error: loading vars file '%s'\n%v\n", varsFile, err)
os.Exit(1)
}

varsExtra, err := varsFromString(varsInline)
if err != nil {
fmt.Printf("Error: loading inline vars\n%v\n", err)
os.Exit(1)
}

for k, v := range varsExtra {
vars[k] = v
}

tVars := &TmplVars{Vars: vars}

f := func(data []byte) []byte {
funcMap := funcMap
t := template.New("test").Funcs(template.FuncMap(funcMap))
t := template.New("test").Funcs(funcMap)
tmpl, err := t.Parse(string(data))
if err != nil {
log.Fatal(err)
Expand Down
4 changes: 3 additions & 1 deletion validate.go
Expand Up @@ -22,7 +22,9 @@ func getGossConfig(c *cli.Context) GossConfig {
var fh *os.File
var path, source string
var gossConfig GossConfig
TemplateFilter = NewTemplateFilter(c.GlobalString("vars"))
varsFile := c.GlobalString("vars")
varsInline := c.GlobalString("vars-inline")
TemplateFilter = NewTemplateFilter(varsFile, varsInline)
specFile := c.GlobalString("gossfile")
if specFile == "-" {
source = "STDIN"
Expand Down

0 comments on commit e9e37b0

Please sign in to comment.