github.com/jlmeeker/kismatic@v1.10.1-0.20180612190640-57f9005a1f1a/pkg/inspector/rule/engine.go (about) 1 package rule 2 3 import ( 4 "sync" 5 6 "github.com/apprenda/kismatic/pkg/inspector/check" 7 ) 8 9 // The Engine executes rules and reports the results 10 type Engine struct { 11 RuleCheckMapper CheckMapper 12 mu sync.Mutex 13 closableChecks []check.ClosableCheck 14 } 15 16 // ExecuteRules runs the rules that should be executed according to the facts, 17 // and returns a collection of results. The number of results is not guaranteed 18 // to equal the number of rules. 19 func (e *Engine) ExecuteRules(rules []Rule, facts []string) ([]Result, error) { 20 results := []Result{} 21 for _, rule := range rules { 22 if !shouldExecuteRule(rule, facts) { 23 continue 24 } 25 26 // Map the rule to a check 27 c, err := e.RuleCheckMapper.GetCheckForRule(rule) 28 if err != nil { 29 return nil, err 30 } 31 32 // Run the check and report result 33 ok, err := c.Check() 34 res := Result{ 35 Name: rule.Name(), 36 Success: ok, 37 Remediation: "", 38 } 39 if err != nil { 40 res.Error = err.Error() 41 } 42 43 // We update the closables as we go to avoid leaking closables 44 // in the event where we have to return an error from within the loop. 45 if closeable, ok := c.(check.ClosableCheck); ok && res.Success { 46 e.mu.Lock() 47 e.closableChecks = append(e.closableChecks, closeable) 48 e.mu.Unlock() 49 } 50 51 results = append(results, res) 52 } 53 return results, nil 54 } 55 56 // CloseChecks that need to be closed 57 func (e *Engine) CloseChecks() error { 58 e.mu.Lock() 59 defer e.mu.Unlock() 60 for _, c := range e.closableChecks { 61 if err := c.Close(); err != nil { 62 // TODO: Figure out what to do with the error here 63 } 64 } 65 e.closableChecks = []check.ClosableCheck{} 66 return nil 67 } 68 69 func shouldExecuteRule(rule Rule, facts []string) bool { 70 // Run if and only if the all the conditions on the rule are 71 // satisfied by the facts 72 for _, whenSlice := range rule.GetRuleMeta().When { 73 found := false 74 for _, whenCondition := range whenSlice { 75 for _, l := range facts { 76 if whenCondition == l { 77 found = true 78 break 79 } 80 } 81 if found { 82 break 83 } 84 } 85 if !found { 86 return false 87 } 88 } 89 return true 90 }