I was wondering if you can point me in the right direction. I would like to write a rules-based system to audit a set of machines -- for example
- Check configuration parameters to see if they were set correctly
- Check state of machines to see if they are at acceptable ranges
The thing that I am struggling with is coming up with a grammar for the auditing rules so that I don't have to code defrules. I created some simple auditing rules but I am struggling with coming up with a generic form.
Here is my current attempt.
First, I am currently representing configuration parameters and running state with a single template (for a lack of imagination, I called it audit-fact) so that my auditing language can work for both configuration and state. I use the domain slot to specify configuration vs. state.
(deftemplate audit-fact
(slot domain (allowed-values config state)) ;; config vs. state
(slot machine) ;; machine to audit
(slot name) ;; parameter or state to check/audit
(slot value) ;; parameter value
(slot already-checked (default FALSE))
)
Next, I wrote a program to read in and assert the machines configuration and state as audit-facts. The following are sample configuration and state audit-facts
(assert (audit-fact
(domain config)
(machine drl-a-15_0)
(name os-version) (value 5.5))
)
(assert (audit-fact
(domain state)
(machine drl-a-15_0)
(name rpm) (value 5023))
)
Here is my current attempt at an auditing grammar/language ---
(deftemplate rule
(slot domain)
(slot name)
(slot constraint (default ?NONE) (allowed-values should-remain-at-default should-equal should-be-between ignore-if-ends-with))
(multislot values)
(multislot reasons)
(multislot references)
(slot criticality (allowed-values critical info suggestion warning))
(slot already-checked (default FALSE))
)
The following rule is used to check if a state or parameter is within a certain range
(assert (rule
(domain state)
(name rpm)
(constraint should-be-between)
(values 5000 5500)
(criticality critical)
(reasons "Low values could cause engine to stall. Prolonged high value could cause engine to heat up") )
)
Next, I used the following rule to check that a state or parameter is equal to a specific value
(assert (rule
(domain config)
(name os-version)
(constraint should-equal)
(values 5.5)
(criticality critical)
(reasons "OS version must be at 5.5 – no other levels are currently certified.") )
)
The following rules implements the equal and between checks
(defrule rule-should-eq
(rule (domain ?d) (name ?n) (constraint should-equal) (values ?cv) (reasons ?r))
?p <- (audit-fact (domain ?d) (name ?n) (value ?v) (already-checked FALSE))
=>
(if (eq ?v ?cv)
then
(printout t "checking " ?d ": " ?n ". Passed " crlf)
else
(printout t "checking " ?d “: “ ?n " should be set to " ?cv ". " ?r ". Warning" crlf)
)
(modify ?p (already-checked TRUE))
)
(defrule rule-should-be-between
(rule (domain ?d) (name ?n) (constraint should-be-between) (values ?cv-low ?cv-high) (reasons ?r))
?p <- (audit-fact (domain ?d) (name ?n) (value ?v) (already-checked FALSE))
=>
(if (and (>= ?v ?cv-low) (<= ?v ?cv-high))
then
(printout t "checking " ?n ". Passed " crlf)
else
(printout t "checking " ?n " should be between " ?cv-low " and " ?cv-high ". " ?r ". Warning" crlf)
)
(modify ?p (already-checked TRUE))
)
Using the above, I can implement simple checks -- e.g., must-be-set-to, must-be-between, must-not-equal, must-remain-at-default-value, must-be-higher-than, must-be-lower-than, etc.
But I can't think of an easy way to make the grammar handle multiple conditions with ands or ors, etc.
Question ---
- is there a paper that describes a design pattern for auditing rules like above. I am currently studying the wine.clp in examples (CLIPS).
- should I give up and just use the simple grammar for simple auditing rules and just use defrules for anything complicated -- e.g., if config-A is set to X, then check five other configs to make sure they are also set correctly, and then assert a check of the state. Once asserted, then check the state to be within a certain range.
Thanks in advance.
Bernie