Skip to content

Commit

Permalink
handle nested maps
Browse files Browse the repository at this point in the history
  • Loading branch information
drlau committed Feb 1, 2021
1 parent 93a1909 commit d3ace99
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 66 deletions.
82 changes: 18 additions & 64 deletions pkg/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,69 +43,19 @@ func NewResourceFromConfig(resourceIdentifier ruleset.ResourceIdentifier, resour
}

func (r *resource) CompareResult(values map[string]interface{}) *CompareResult {
enforcedArgs := make(map[string]interface{})
failedArgs := make(map[string]interface{})
ignored := make(map[string]interface{})
extraArgs := make(map[string]interface{})

// Passed in the plan's values
// Iterate over each key/value
for k, v := range values {
// If the key is ignored, record and continue
if _, ok := r.Ignored[k]; ok {
ignored[k] = true
continue
}
// If the key is enforced...
if enforced, ok := r.Enforced[k]; ok {
switch {
case enforced.Value != nil:
// Verify the value is what is expected
if !equal(enforced.Value, v) {
// Not equal - record as failed
failedArgs[k] = FailedArg{
Expected: enforced.Value,
Actual: v,
}
} else {
// equal
enforcedArgs[k] = enforced
}
case enforced.MatchAny != nil:
found := false
for _, val := range enforced.MatchAny {
// Verify the value is what is expected
if equal(val, v) {
// equal
enforcedArgs[k] = enforced
found = true
break
}
}
if !found {
failedArgs[k] = FailedArg{
Expected: fmt.Sprintf("one of: %v", enforced.MatchAny),
Actual: v,
MatchAny: true,
}
}
default:
// TODO: Tests that key exists and that's it - intended?
}
// key is not enforced or ignored
} else {
extraArgs[k] = true
}
result := &CompareResult{
Enforced: make(map[string]interface{}),
Failed: make(map[string]interface{}),
Ignored: make(map[string]interface{}),
Extra: make(map[string]interface{}),
}

return &CompareResult{
Enforced: enforcedArgs,
Failed: failedArgs,
Ignored: ignored,
Extra: extraArgs,
MissingEnforced: setDifference(enforcedSetDifference(r.Enforced, enforcedArgs), failedArgs),
MissingIgnored: setDifference(setDifference(r.Ignored, ignored), failedArgs),
}
result.checkValues(r.Enforced, r.Ignored, values, "")

result.MissingEnforced = setDifference(enforcedSetDifference(make(map[string]interface{}), "", r.Enforced, result.Enforced), result.Failed)
result.MissingIgnored = setDifference(setDifference(r.Ignored, result.Ignored), result.Failed)

return result
}

func (r *resource) Compare(rv ResourceValues) bool {
Expand Down Expand Up @@ -206,10 +156,14 @@ func setDifference(a, b map[string]interface{}) map[string]interface{} {

// enforcedSetDifference returns elements in A but not in B
// only checks for key equality - ignores values
func enforcedSetDifference(a map[string]ruleset.EnforceChange, b map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
func enforcedSetDifference(result map[string]interface{}, keyPrefix string, a map[string]ruleset.EnforceChange, b map[string]interface{}) map[string]interface{} {
for k, v := range a {
if _, ok := b[k]; !ok {
if keyPrefix != "" {
k = fmt.Sprintf("%s.%s", keyPrefix, k)
}
if v.EnforceChange != nil {
result = enforcedSetDifference(result, k, v.EnforceChange, b)
} else if _, ok := b[k]; !ok {
result[k] = v
}
}
Expand Down
31 changes: 31 additions & 0 deletions pkg/resource/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,37 @@ func TestResourceCompareResult(t *testing.T) {
},
},
},
"nested enforced value": {
resource: &resource{
Enforced: map[string]ruleset.EnforceChange{
"key": {
EnforceChange: map[string]ruleset.EnforceChange{
"nested-key": {
Value: true,
},
},
},
},
CompareOptions: &CompareOptions{},
},
values: map[string]interface{}{
"key": map[string]interface{}{
"nested-key": true,
},
},
expected: &CompareResult{
Enforced: map[string]interface{}{
"key.nested-key": ruleset.EnforceChange{
Value: true,
},
},
Failed: map[string]interface{}{},
Ignored: map[string]interface{}{},
Extra: map[string]interface{}{},
MissingEnforced: map[string]interface{}{},
MissingIgnored: map[string]interface{}{},
},
},
}

for name, tc := range cases {
Expand Down
70 changes: 70 additions & 0 deletions pkg/resource/result.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package resource

import (
"fmt"

"github.com/drlau/akashi/pkg/ruleset"
)

type CompareResult struct {
// args that had a matching EnforcedValue and are equal
Enforced map[string]interface{}
Expand All @@ -20,6 +26,70 @@ type CompareResult struct {
MissingIgnored map[string]interface{}
}

func (cr *CompareResult) checkValues(enforced map[string]ruleset.EnforceChange, ignored map[string]interface{}, values map[string]interface{}, keyPrefix string) {
// Passed in the plan's values
// Iterate over each key/value
for k, v := range values {
key := k
if keyPrefix != "" {
key = fmt.Sprintf("%s.%s", keyPrefix, k)
}
// If the key is ignored, record and continue
if _, ok := ignored[k]; ok {
// TODO: handle nested ignore
cr.Ignored[k] = true
continue
}
// If the key is enforced...
if enforced, ok := enforced[k]; ok {
switch {
case enforced.Value != nil:
// Verify the value is what is expected
if !equal(enforced.Value, v) {
// Not equal - record as failed
cr.Failed[key] = FailedArg{
Expected: enforced.Value,
Actual: v,
}
} else {
// equal
cr.Enforced[key] = enforced
}
case enforced.MatchAny != nil:
found := false
for _, val := range enforced.MatchAny {
// Verify the value is what is expected
if equal(val, v) {
// equal
cr.Enforced[key] = enforced
found = true
break
}
}
if !found {
cr.Failed[key] = FailedArg{
Expected: fmt.Sprintf("one of: %v", enforced.MatchAny),
Actual: v,
MatchAny: true,
}
}
case enforced.EnforceChange != nil:
casted, ok := values[k].(map[string]interface{})
if ok {
cr.checkValues(enforced.EnforceChange, ignored, casted, k)
} else {
// failed
fmt.Println("failed to cast - failed enforced")
}
default:
// TODO: Tests that key exists and that's it - intended?
}
} else {
cr.Extra[key] = true
}
}
}

func (cr *CompareResult) GetEnforced() map[string]interface{} {
return cr.Enforced
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/ruleset/ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ type ResourceRules struct {
}

type EnforceChange struct {
Value interface{} `yaml:"value,omitempty"`
MatchAny []interface{} `yaml:"matchAny,omitempty"`
Value interface{} `yaml:"value,omitempty"`
MatchAny []interface{} `yaml:"matchAny,omitempty"`
EnforceChange map[string]EnforceChange `yaml:",inline"`
}

0 comments on commit d3ace99

Please sign in to comment.