CORD-1389: xproto extension to support policies
Change-Id: I5d6c11107d5bc9cd82e41c4a8e6a378d22d7fb61
diff --git a/lib/xos-genx/tests/policy_test.py b/lib/xos-genx/tests/policy_test.py
new file mode 100644
index 0000000..5f1dca0
--- /dev/null
+++ b/lib/xos-genx/tests/policy_test.py
@@ -0,0 +1,119 @@
+import unittest
+from xosgenx.generator import XOSGenerator
+from helpers import FakeArgs, XProtoTestHelpers
+import pdb
+
+"""
+The tests below convert the policy logic expression
+into Python, set up an appropriate environment and execute the Python.
+"""
+
+class XProtoPolicyTest(unittest.TestCase):
+ def test_constant(self):
+ xproto = \
+"""
+ policy true_policy < True >
+"""
+
+ target = XProtoTestHelpers.write_tmp_target("{{ proto.policies.true_policy }}")
+
+ args = FakeArgs()
+ args.inputs = xproto
+ args.target = target
+
+ output = XOSGenerator.generate(args).replace('t','T')
+ self.assertTrue(eval(output))
+
+ def test_equal(self):
+ xproto = \
+"""
+ policy slice_user < slice.user = obj.user >
+"""
+
+ target = XProtoTestHelpers.write_tmp_target("{{ proto.policies.slice_user }}")
+ args = FakeArgs()
+ args.inputs = xproto
+ args.target = target
+
+ output = XOSGenerator.generate(args)
+
+ slice = FakeArgs()
+ slice.user = 'twin'
+ obj = FakeArgs()
+ obj.user = 'twin'
+
+ (op, operands), = eval(output).items()
+ expr = op.join(operands).replace('=','==')
+
+ self.assertTrue(eval(expr))
+
+ def test_bin(self):
+ xproto = \
+"""
+ policy slice_admin < slice.is_admin | obj.empty >
+"""
+ target = XProtoTestHelpers.write_tmp_target("{{ proto.policies.slice_admin }}")
+ args = FakeArgs()
+ args.inputs = xproto
+ args.target = target
+
+ output = XOSGenerator.generate(args)
+
+ slice = FakeArgs()
+ slice.is_admin = False
+ obj = FakeArgs()
+ obj.empty = []
+
+ (op, operands), = eval(output).items()
+ expr = op.join(operands).replace('|',' or ')
+
+ self.assertFalse(eval(expr))
+
+
+ def test_exists(self):
+ xproto = \
+"""
+ policy privilege < exists Privilege: Privilege.object_id = obj.id >
+"""
+
+ target = XProtoTestHelpers.write_tmp_target("{{ proto.policies.privilege }} ")
+ args = FakeArgs()
+ args.inputs = xproto
+ args.target = target
+
+ output = XOSGenerator.generate(args)
+
+ Privilege = FakeArgs()
+ Privilege.object_id = 1
+ obj = FakeArgs()
+ obj.id = 1
+
+ (op, operands), = eval(output).items()
+ (op2, operands2), = operands[1].items()
+ expr = op2.join(operands2).replace('=','==')
+
+ self.assertTrue(eval(expr))
+
+ def test_forall(self):
+ # This one we only parse
+ xproto = \
+"""
+ policy instance < forall Instance: exists Credential: Credential.obj_id = Instance.obj_id >
+"""
+
+ target = XProtoTestHelpers.write_tmp_target("{{ proto.policies.instance }}")
+
+ args = FakeArgs()
+ args.inputs = xproto
+ args.target = target
+
+ output = XOSGenerator.generate(args)
+ (op, operands), = eval(output).items()
+
+ self.assertEqual(op,'forall')
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
diff --git a/lib/xos-genx/xosgenx/generator.py b/lib/xos-genx/xosgenx/generator.py
index 668d351..8a4e1a8 100755
--- a/lib/xos-genx/xosgenx/generator.py
+++ b/lib/xos-genx/xosgenx/generator.py
@@ -191,11 +191,13 @@
models = {}
models[model] = v.models[model]
messages = [XOSGenerator._find_message_by_model_name(v.messages, model)]
+
rendered[model] = template.render(
{"proto":
{
'message_table': models,
'messages': messages,
+ 'policies': v.policies,
'message_names': [m['name'] for m in messages]
},
"context": context,
@@ -209,6 +211,7 @@
{
'message_table': v.models,
'messages': v.messages,
+ 'policies': v.policies,
'message_names': [m['name'] for m in v.messages]
},
"context": context,
diff --git a/lib/xos-genx/xosgenx/proto2xproto.py b/lib/xos-genx/xosgenx/proto2xproto.py
index f05c2bc..3723e7c 100644
--- a/lib/xos-genx/xosgenx/proto2xproto.py
+++ b/lib/xos-genx/xosgenx/proto2xproto.py
@@ -1,4 +1,5 @@
import plyxproto.model as m
+from plyxproto.helpers import Visitor
import pdb
import argparse
import plyxproto.parser as plyxproto
@@ -47,7 +48,7 @@
except:
return obj
-class Proto2XProto(m.Visitor):
+class Proto2XProto(Visitor):
def __init__(self):
super(Proto2XProto, self).__init__()
diff --git a/lib/xos-genx/xosgenx/xos2jinja.py b/lib/xos-genx/xosgenx/xos2jinja.py
index 929526d..c58260e 100644
--- a/lib/xos-genx/xosgenx/xos2jinja.py
+++ b/lib/xos-genx/xosgenx/xos2jinja.py
@@ -1,5 +1,5 @@
import plyxproto.model as m
-import pdb
+from plyxproto.helpers import Visitor
import argparse
import plyxproto.parser as plyxproto
import traceback
@@ -64,7 +64,6 @@
try:
rev_links[l['peer']['fqn']].append(rlink)
except TypeError:
- pdb.set_trace()
pass
except KeyError:
rev_links[l['peer']['fqn']] = [rlink]
@@ -97,12 +96,7 @@
''' XOS2Jinja overrides the underlying visitor pattern to transform the tree
in addition to traversing it '''
-
-class XOS2Jinja(m.Visitor):
-
- def get_stack(self):
- return self.stack
-
+class XOS2Jinja(Visitor):
def __init__(self):
super(XOS2Jinja, self).__init__()
@@ -112,6 +106,7 @@
self.package = None
self.message_options = {}
self.count_stack = Stack()
+ self.policies = {}
self.content = ""
self.offset = 0
self.current_message_name = None
@@ -119,6 +114,16 @@
self.first_field = True
self.first_method = True
+ def visit_PolicyDefinition(self, obj):
+ if self.package:
+ pname = '.'.join([self.package, obj.name.value.pval])
+ else:
+ pname = obj.name.value.pval
+
+ self.policies[pname] = obj.body
+
+ return True
+
def visit_PackageStatement(self, obj):
dotlist = obj.name.value
dotlist2 = [f.pval for f in dotlist]
@@ -177,6 +182,10 @@
s['src_port'] = obj.src_port.value.pval
s['name'] = obj.src_port.value.pval
+ try:
+ s['policy'] = obj.policy.pval
+ except AttributeError:
+ s['policy'] = None
try:
s['dst_port'] = obj.dst_port.value.pval
@@ -218,6 +227,12 @@
s['type'] = obj.ftype.name.pval
s['name'] = obj.name.value.pval
+
+ try:
+ s['policy'] = obj.policy.pval
+ except AttributeError:
+ s['policy'] = None
+
s['modifier'] = obj.field_modifier.pval
s['id'] = obj.fieldId.pval
@@ -293,6 +308,11 @@
model_name = obj.name.value.pval
model_def = {'name':obj.name.value.pval,'fields':fields,'links':links, 'bases':obj.bases, 'options':self.message_options, 'package':self.package, 'fqn': model_name, 'rlinks': []}
+ try:
+ model_def['policy'] = obj.policy.pval
+ except AttributeError:
+ model_def['policy'] = None
+
self.stack.push(model_def)
self.models[model_name] = model_def
@@ -352,4 +372,4 @@
def visit_LinkSpec(self, obj):
count = self.count_stack.pop()
self.count_stack.push(count + 1)
- return True
\ No newline at end of file
+ return True
diff --git a/xos/coreapi/protos/Makefile b/xos/coreapi/protos/Makefile
index ad9ba1f..cfbaa52 100644
--- a/xos/coreapi/protos/Makefile
+++ b/xos/coreapi/protos/Makefile
@@ -102,4 +102,4 @@
rebuild-protos: $(AUTOGENERATED)
-.PHONY: $(AUTOGENERATED) rebuild-protos
\ No newline at end of file
+.PHONY: $(AUTOGENERATED) rebuild-protos
diff --git a/xos/tools/corebuilder/corebuilder.py b/xos/tools/corebuilder/corebuilder.py
index be8702e..845e7c7 100644
--- a/xos/tools/corebuilder/corebuilder.py
+++ b/xos/tools/corebuilder/corebuilder.py
@@ -301,7 +301,6 @@
# Generate models
is_service = service_name != 'core'
-
args = Args()
args.output = build_dest_fn
args.attic = src_fn + '/attic'
@@ -328,8 +327,8 @@
XOSGenerator.generate(InitArgs())
except Exception, e:
- print e
- raise Exception('xproto build failed!')
+ print 'xproto build failed.'
+ raise e
# Create the __init__.py files
@@ -386,10 +385,3 @@
if __name__ == "__main__":
main()
-
-
-
-
-
-
-