Extended example to include remediation
The private/public network example now includes a step that asks for remediations. All tests pass Issue: # Change-Id: I6f341c6cc74040288b4ef67e776bf079f3346624
This commit is contained in:
parent
ef84b421b5
commit
1734809fe7
|
@ -1,17 +1,17 @@
|
|||
|
||||
|
||||
// disconnect_network action
|
||||
action(disconnect_network)
|
||||
action("disconnect_network")
|
||||
nova:network-(vm, network) :- disconnect_network(vm, network)
|
||||
|
||||
// delete_vm action
|
||||
action(delete_vm)
|
||||
action("delete_vm")
|
||||
nova:virtual_machine-(vm) :- delete_vm(vm)
|
||||
nova:network-(vm, network) :- delete_vm(vm), nova:network(vm, network)
|
||||
nova:owner-(vm, owner) :- delete_vm(vm), nova:owner(vm, owner)
|
||||
|
||||
// make_public action
|
||||
action(make_public)
|
||||
action("make_public")
|
||||
neutron:public_network+(network) :- make_public(network)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
. script for a demo.
|
||||
Script for a demo.
|
||||
|
||||
0) Example policy
|
||||
|
||||
|
@ -97,3 +97,34 @@ error(vm3)
|
|||
-------------------------------------------------
|
||||
|
||||
|
||||
10) Install Action theory
|
||||
|
||||
// disconnect_network action
|
||||
action("disconnect_network")
|
||||
nova:network-(vm, network) :- disconnect_network(vm, network)
|
||||
|
||||
// delete_vm action
|
||||
action("delete_vm")
|
||||
nova:virtual_machine-(vm) :- delete_vm(vm)
|
||||
nova:network-(vm, network) :- delete_vm(vm), nova:network(vm, network)
|
||||
nova:owner-(vm, owner) :- delete_vm(vm), nova:owner(vm, owner)
|
||||
|
||||
// make_public action
|
||||
action("make_public")
|
||||
neutron:public_network+(network) :- make_public(network)
|
||||
|
||||
--- Commands ------------------------------------
|
||||
>>> r.load_file("../../examples/private_public_network.action", target=r.ACTION_THEORY)
|
||||
-------------------------------------------------
|
||||
|
||||
|
||||
11) Ask for remediations: actions that when executed will fix a violation
|
||||
|
||||
--- Commands ------------------------------------
|
||||
print r.remediate('error("vm1")')
|
||||
nova:virtual_machine-(vm1) :- delete_vm(vm1)
|
||||
nova:network-(vm1, net_private) :- disconnect_network(vm1, net_private)
|
||||
neutron:public_network+(net_private) :- make_public(net_private)
|
||||
nova:owner-(vm1, tim) :- delete_vm(vm1)
|
||||
-------------------------------------------------
|
||||
|
||||
|
|
|
@ -95,11 +95,11 @@ class Variable (Term):
|
|||
return not self == other
|
||||
|
||||
def __repr__(self):
|
||||
return "Variable(name={}, location={})".format(
|
||||
repr(self.name), repr(self.location))
|
||||
# Use repr to hash rule--can't include location
|
||||
return "Variable(name={})".format(repr(self.name))
|
||||
|
||||
def __hash__(self):
|
||||
return hash("Variable(name={})".format(repr(self.name)))
|
||||
return hash(repr(self))
|
||||
|
||||
def is_variable(self):
|
||||
return True
|
||||
|
@ -123,12 +123,12 @@ class ObjectConstant (Term):
|
|||
return str(self.name)
|
||||
|
||||
def __repr__(self):
|
||||
return "ObjectConstant(name={}, type={}, location={})".format(
|
||||
repr(self.name), repr(self.type), repr(self.location))
|
||||
# Use repr to hash rule--can't include location
|
||||
return "ObjectConstant(name={}, type={})".format(
|
||||
repr(self.name), repr(self.type))
|
||||
|
||||
def __hash__(self):
|
||||
return hash("ObjectConstant(name={}, type={})".format(
|
||||
repr(self.name), repr(self.type)))
|
||||
return hash(repr(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
return (isinstance(other, ObjectConstant) and
|
||||
|
@ -181,15 +181,13 @@ class Atom (object):
|
|||
return not self == other
|
||||
|
||||
def __repr__(self):
|
||||
return "Atom(table={}, arguments={}, location={})".format(
|
||||
# Use repr to hash rule--can't include location
|
||||
return "Atom(table={}, arguments={})".format(
|
||||
repr(self.table),
|
||||
"[" + ",".join(repr(arg) for arg in self.arguments) + "]",
|
||||
repr(self.location))
|
||||
"[" + ",".join(repr(arg) for arg in self.arguments) + "]")
|
||||
|
||||
def __hash__(self):
|
||||
return hash("Atom(table={}, arguments={})".format(
|
||||
repr(self.table),
|
||||
"[" + ",".join(repr(arg) for arg in self.arguments) + "]"))
|
||||
return hash(repr(self))
|
||||
|
||||
def is_atom(self):
|
||||
return True
|
||||
|
@ -252,10 +250,10 @@ class Literal(Atom):
|
|||
return (self.negated == other.negated and Atom.__eq__(self, other))
|
||||
|
||||
def __repr__(self):
|
||||
return "Literal(table={}, arguments={}, location={}, negated={})".format(
|
||||
# Use repr to hash rule--can't include location
|
||||
return "Literal(table={}, arguments={}, negated={})".format(
|
||||
repr(self.table),
|
||||
"[" + ",".join(repr(arg) for arg in self.arguments) + "]",
|
||||
repr(self.location),
|
||||
repr(self.negated))
|
||||
|
||||
def __hash__(self):
|
||||
|
@ -310,6 +308,7 @@ class Rule (object):
|
|||
repr(self.location))
|
||||
|
||||
def __hash__(self):
|
||||
# won't properly treat a positive literal and an atom as the same
|
||||
return hash("Rule(head={}, body={})".format(
|
||||
repr(self.head),
|
||||
"[" + ",".join(repr(arg) for arg in self.body) + "]"))
|
||||
|
@ -342,6 +341,8 @@ def formulas_to_string(formulas):
|
|||
""" Takes an iterable of compiler sentence objects and returns a
|
||||
string representing that iterable, which the compiler will parse
|
||||
into the original iterable. """
|
||||
if formulas is None:
|
||||
return "None"
|
||||
return " ".join([str(formula) for formula in formulas])
|
||||
|
||||
##############################################################################
|
||||
|
|
|
@ -871,7 +871,10 @@ class MaterializedRuleTheory(TopDownTheory):
|
|||
# ignoring TABLENAMES and FIND_ALL
|
||||
# except that we return the proper type.
|
||||
proof = self.explain_aux(query, 0)
|
||||
return [proof]
|
||||
if proof is None:
|
||||
return None
|
||||
else:
|
||||
return [proof]
|
||||
|
||||
############### Interface implementation ###############
|
||||
|
||||
|
@ -886,6 +889,8 @@ class MaterializedRuleTheory(TopDownTheory):
|
|||
return Proof(query, [])
|
||||
# grab first local proof, since they're all equally good
|
||||
localproofs = self.database.explain(query)
|
||||
if localproofs is None:
|
||||
return None
|
||||
if len(localproofs) == 0: # base fact
|
||||
return Proof(query, [])
|
||||
localproof = localproofs[0]
|
||||
|
@ -1107,6 +1112,23 @@ class Runtime (object):
|
|||
def log(self, table, msg, depth=0):
|
||||
self.tracer.log(table, "RT: " + msg, depth)
|
||||
|
||||
def debug_mode(self):
|
||||
tracer = Tracer()
|
||||
tracer.trace('*')
|
||||
self.tracer = tracer
|
||||
self.theory[self.CLASSIFY_THEORY].tracer = tracer
|
||||
self.theory[self.SERVICE_THEORY].tracer = tracer
|
||||
self.theory[self.ACTION_THEORY].tracer = tracer
|
||||
self.theory[self.CLASSIFY_THEORY].database.tracer = tracer
|
||||
|
||||
def production_mode(self):
|
||||
tracer = Tracer()
|
||||
self.tracer = tracer
|
||||
self.theory[self.CLASSIFY_THEORY].tracer = tracer
|
||||
self.theory[self.SERVICE_THEORY].tracer = tracer
|
||||
self.theory[self.ACTION_THEORY].tracer = tracer
|
||||
self.theory[self.CLASSIFY_THEORY].database.tracer = tracer
|
||||
|
||||
############### External interface ###############
|
||||
def load_file(self, filename, target=None):
|
||||
""" Compile the given FILENAME and insert each of the statements
|
||||
|
@ -1272,9 +1294,9 @@ class Runtime (object):
|
|||
else:
|
||||
goal.table = goal.table + "-"
|
||||
# return is a list of goal :- act1, act2, ...
|
||||
# Turn it into a list of output :- act1, act2, ...
|
||||
# This is more informative than query :- act1, act2, ...
|
||||
for abduction in actionth.abduce(goal, actions, False):
|
||||
results.append(compile.Rule(output, abduction.body))
|
||||
results.append(abduction)
|
||||
return results
|
||||
|
||||
def remediate_string(self, policy_string, theory):
|
||||
|
|
|
@ -21,13 +21,7 @@ class TestRuntime(unittest.TestCase):
|
|||
code = ""
|
||||
run = runtime.Runtime()
|
||||
run.insert(code, target=target)
|
||||
tracer = runtime.Tracer()
|
||||
tracer.trace('*')
|
||||
run.tracer = tracer
|
||||
run.theory[run.CLASSIFY_THEORY].tracer = tracer
|
||||
run.theory[run.SERVICE_THEORY].tracer = tracer
|
||||
run.theory[run.ACTION_THEORY].tracer = tracer
|
||||
run.theory[run.CLASSIFY_THEORY].database.tracer = tracer
|
||||
run.debug_mode()
|
||||
return run
|
||||
|
||||
def insert(self, run, alist):
|
||||
|
@ -947,7 +941,7 @@ class TestRuntime(unittest.TestCase):
|
|||
'p-(x) :- a(x)')
|
||||
class_code = ('err(x) :- p(x)'
|
||||
'p(1)')
|
||||
check(action_code, class_code, 'err(1)', 'err(1) :- a(1)', 'Monadic')
|
||||
check(action_code, class_code, 'err(1)', 'p-(1) :- a(1)', 'Monadic')
|
||||
|
||||
# rules in action theory
|
||||
action_code = ('action("a")'
|
||||
|
@ -955,7 +949,7 @@ class TestRuntime(unittest.TestCase):
|
|||
'q(x) :- a(x)')
|
||||
class_code = ('err(x) :- p(x)'
|
||||
'p(1)')
|
||||
check(action_code, class_code, 'err(1)', 'err(1) :- a(1)',
|
||||
check(action_code, class_code, 'err(1)', 'p-(1) :- a(1)',
|
||||
'Monadic, indirect')
|
||||
|
||||
# multiple conditions in error
|
||||
|
@ -967,7 +961,7 @@ class TestRuntime(unittest.TestCase):
|
|||
'p(1)'
|
||||
'q(1)')
|
||||
check(action_code, class_code, 'err(1)',
|
||||
'err(1) :- a(1) err(1) :- b(1)',
|
||||
'p-(1) :- a(1) q-(1) :- b(1)',
|
||||
'Monadic, two conditions, two actions')
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue