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  }