Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Epiphyte synprop req #409

Merged
merged 17 commits into from
Aug 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion synapse/cores/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,9 @@ def addTufoEvents(self, form, propss):

self._addDefProps(form, fulls)

# Ensure we have ALL the required props
self._reqProps(form, fulls)

fulls[form] = iden
fulls['tufo:form'] = form

Expand Down Expand Up @@ -1878,6 +1881,26 @@ def _runAutoAdd(self, toadd):
continue
self.formTufoByProp(form, valu)

def _reqProps(self, form, fulls):
if not self.enforce:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if enforce mode is off, required props are not required. (thinking aloud)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vertexmc this is per @invisig0th

return

props = self.getFormReqs(form)

# Return fast for perf
if not props:
return

# Special case for handling syn:prop:glob=1 on will not have a ptype
# despite the model requiring a ptype to be present.
if fulls.get('syn:prop:glob'):
props.pop('syn:prop:ptype', None)

missing = set(props) - set(fulls)
if missing:
raise s_common.PropNotFound(mesg='Node is missing required a prop during formation',
prop=list(missing)[0], form=form)

def formTufoByTufo(self, tufo):
'''
Form an (iden,info) tufo by extracting information from an existing one.
Expand Down Expand Up @@ -1972,6 +1995,9 @@ def formTufoByProp(self, prop, valu, **props):
# create a "full" props dict which includes defaults
self._addDefProps(prop, fulls)

# Ensure we have ALL the required props
self._reqProps(prop, fulls)

fulls[prop] = valu
fulls['tufo:form'] = prop

Expand Down Expand Up @@ -2441,7 +2467,7 @@ def setTufoProps(self, tufo, **props):
xact.fire('node:prop:set', form=form, valu=valu, prop=p, newv=v, oldv=oldv, node=tufo)

# fire the splice event
xact.spliced('node:prop:set', form=form, valu=valu, prop=p[len(form)+1:], newv=v, oldv=oldv, node=tufo)
xact.spliced('node:prop:set', form=form, valu=valu, prop=p[len(form) + 1:], newv=v, oldv=oldv, node=tufo)

if self.autoadd:
self._runAutoAdd(toadd)
Expand Down
23 changes: 21 additions & 2 deletions synapse/datamodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def __init__(self, load=True):
self.props = {}
self.forms = set()

self.reqprops = collections.defaultdict(list)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call on keeping these in an optimized lookup

self.defvals = collections.defaultdict(list)
self.subprops = collections.defaultdict(list)
self.propsbytype = collections.defaultdict(list)
Expand All @@ -125,10 +126,11 @@ def __init__(self, load=True):
self.addTufoProp('syn:form', 'ptype', ptype='syn:type', req=1, doc='Synapse type for this form')

self.addTufoForm('syn:prop', ptype='syn:prop')
self.addTufoProp('syn:prop', 'doc', ptype='str', req=1, doc='Description of the property definition')
# TODO - Re-enable syn:prop:doc req = 1 after cleaning up property docstrings.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add another story to track adding docstrings for all props and enabling this. We should inform users before enabling this to avoid private models breaking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@therealsilence has a story for doing all these docs already.

self.addTufoProp('syn:prop', 'doc', ptype='str', req=0, doc='Description of the property definition')
self.addTufoProp('syn:prop', 'form', ptype='syn:prop', req=1, doc='Synapse form which contains this property')
self.addTufoProp('syn:prop', 'ptype', ptype='syn:type', req=1, doc='Synapse type for this field')
self.addTufoProp('syn:prop', 'req', ptype='bool', defval=0, doc='Set to 1 if this property is required')
self.addTufoProp('syn:prop', 'req', ptype='bool', defval=0, doc='Set to 1 if this property is required to form the node.')
self.addTufoProp('syn:prop', 'glob', ptype='bool', defval=0, doc='Set to 1 if this property defines a glob')
self.addTufoProp('syn:prop', 'defval', doc='Set to the default value for this property')

Expand Down Expand Up @@ -264,6 +266,7 @@ def addPropDef(self, prop, **info):
raise s_common.DupPropName(name=prop)

info.setdefault('doc', None)
info.setdefault('req', False)
info.setdefault('uniq', False)
info.setdefault('ptype', None)
info.setdefault('title', None)
Expand All @@ -279,6 +282,10 @@ def addPropDef(self, prop, **info):
if defval is not None:
self.defvals[form].append((prop, defval))

req = info.get('req')
if req:
self.reqprops[form].append(prop)

pdef = (prop, info)

ptype = info.get('ptype')
Expand All @@ -299,6 +306,18 @@ def getFormDefs(self, form):
'''
return self.defvals.get(form, ())

def getFormReqs(self, form):
'''
Return a list of prop values which are required form a form.

Args:
form (str): Form to request values for.

Returns:
list: List of required properties needed for making the given form.
'''
return self.reqprops.get(form, ())

def _addSubRefs(self, pdef):
name = pdef[0]
for prop in s_tags.iterTagUp(pdef[0], div=':'):
Expand Down
2 changes: 1 addition & 1 deletion synapse/exc.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class NoInitCore(Exception): pass # API disabled because no cortex
class NoCurrSess(Exception): pass # API requires a current session

class SidNotFound(Exception): pass
class PropNotFound(Exception): pass
class PropNotFound(SynErr): pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should create a story to make all of these Exceptions SynErrs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vertexmc we do have one in our backlog


class HitMaxTime(Exception): pass
class HitMaxRetry(Exception): pass
Expand Down
20 changes: 8 additions & 12 deletions synapse/lib/ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,23 +560,19 @@ def _ingFormInfo(self, core, data, info, scope):
if valu is None:
return

tufo = core.formTufoByProp(form, valu)
if tufo is None:
return

self.fire('gest:prog', act='form')

props = {}
for prop, pnfo in info.get('props', {}).items():
valu = self._get_prop(core, data, pnfo, scope)
if valu is None:
pvalu = self._get_prop(core, data, pnfo, scope)
if pvalu is None:
continue

props[prop] = valu
props[prop] = pvalu

if props:
core.setTufoProps(tufo, **props)
self.fire('gest:prog', act='set')
tufo = core.formTufoByProp(form, valu, **props)
if tufo is None:
return

self.fire('gest:prog', act='form')

for tag in scope.iter('tags'):
core.addTufoTag(tufo, tag)
Expand Down
21 changes: 20 additions & 1 deletion synapse/models/crypto.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import logging

import synapse.common as s_common

from synapse.lib.module import CoreModule, modelrev

logger = logging.getLogger(__name__)

ex_md5 = 'd41d8cd98f00b204e9800998ecf8427e'
ex_sha1 = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
ex_sha256 = 'ad9f4fe922b61e674a09530831759843b1880381de686a43460a76864ca0340c'
Expand All @@ -8,6 +14,19 @@

class CryptoMod(CoreModule):

@modelrev('crypto', 201708231712)
def _revModl201708231712(self):
node = self.core.getTufoByProp('syn:prop', 'rsa:key:mod')
if not node: # pragma: no cover
# Its possible someone deleted their syn:prop=rsa:key:mod node :(
mesg = 'No syn:prop="rsa:key:mod" node found during model revision.'
logger.warning(mesg)
self.core.log(logging.WARNING, mesg=mesg)
return
self.core.delRowsByIdProp(node[0], 'syn:prop:pytpe')
if 'syn:prop:ptype' not in node[1]:
self.core.addRows([(node[0], 'syn:prop:ptype', 'str:hex', s_common.now())])

@staticmethod
def getBaseModels():
modl = {
Expand All @@ -33,7 +52,7 @@ def getBaseModels():
('hash:sha384', {'ptype': 'hash:sha384'}, []),
('hash:sha512', {'ptype': 'hash:sha512'}, []),
('rsa:key', {'ptype': 'rsa:key'}, [
('mod', {'pytpe': 'str:hex', 'doc': 'The modulus'}),
('mod', {'ptype': 'str:hex', 'doc': 'The modulus'}),
('bits', {'ptype': 'int', 'doc': 'The length of the modulus in bits'}),
('pub:exp', {'ptype': 'str:hex', 'doc': 'The public exponent'}),
('priv:exp', {'ptype': 'str:hex', 'doc': 'The private exponent'}),
Expand Down
21 changes: 17 additions & 4 deletions synapse/models/inet.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,11 @@ def _revModl201706121318(self):

@modelrev('inet', 201708141516)
def _revModl201708141516(self):
node = self.core.formTufoByProp('syn:type', 'inet:urlfile') # type: list
if not node:
node = self.core.getTufoByProp('syn:type', 'inet:urlfile')
if not node: # pragma: no cover
# Its possible someone deleted their syn:type=inet:urlfile node :(
mesg = 'No syn:type="inet:urlfile" node found during model revision.'
logger.warn(mesg)
logger.warning(mesg)
self.core.log(logging.WARNING, mesg=mesg)
return
self.core.delRowsByIdProp(node[0], 'syn:type:names')
Expand All @@ -411,6 +411,18 @@ def _revModl201708141516(self):
if 'syn:type:fields' not in node[1]:
self.core.addRows([(node[0], 'syn:type:fields', 'url=inet:url,file=file:bytes', s_common.now())])

@modelrev('inet', 201708231646)
def _revModl201708231646(self):
node = self.core.getTufoByProp('syn:prop', 'inet:ipv4:type')
if not node: # pragma: no cover
# Its possible someone deleted their syn:prop=inet:ipv4:type node :(
mesg = 'No syn:prop="inet:ipv4:type" node found during model revision.'
logger.warning(mesg)
self.core.log(logging.WARNING, mesg=mesg)
return
if 'syn:prop:ptype' not in node[1]:
self.core.addRows([(node[0], 'syn:prop:ptype', 'str', s_common.now())])

@staticmethod
def getBaseModels():
modl = {
Expand Down Expand Up @@ -500,7 +512,8 @@ def getBaseModels():

('inet:ipv4', {'ptype': 'inet:ipv4'}, [
('cc', {'ptype': 'pol:iso2', 'defval': '??'}),
('type', {'defval': '??', 'doc': 'what type of ipv4 address ( uni, multi, priv )'}),
('type', {'ptype': 'str', 'defval': '??',
'doc': 'what type of ipv4 address ( uni, multi, priv )'}),
('asn', {'ptype': 'inet:asn', 'defval': -1}),
]),

Expand Down
21 changes: 21 additions & 0 deletions synapse/tests/test_cortex.py
Original file line number Diff line number Diff line change
Expand Up @@ -2562,6 +2562,27 @@ def test_cortex_formtufosbyprops(self):
for s in ['NoSuchForm', 'name=', 'bad']:
self.isin(s, actual[2][1]['syn:err:errmsg'])

def test_cortex_reqprops(self):

with s_cortex.openurl('ram:///') as core:
# TODO - We will have to invert the logic here slightly when enforce=1 is merged.

# Required prop "time" not provided but enforce=0.
t0 = core.addTufoEvent('inet:dns:look', a='WOOT.com/1.2.3.4')
self.nn(t0)

# enable enforce
core.setConfOpt('enforce', 1)

# fails without required prop present
self.raises(PropNotFound, core.addTufoEvent, 'inet:dns:look', a='WOOT.com/1.2.3.5', )

# Works with required prop present
tick = now()
t1 = core.addTufoEvent('inet:dns:look', a='WOOT.com/1.2.3.4', time=tick)
self.eq(t1[1].get('inet:dns:look:time'), tick)
self.ne(t0[0], t1[0])

class StorageTest(SynTest):

def test_nonexist_ctor(self):
Expand Down
2 changes: 1 addition & 1 deletion synapse/tests/test_datamodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def test_datamodel_getPropDef(self):
model.addTufoForm('foo')
model.addTufoProp('foo', 'meow', ptype='int')

self.eq(model.getPropDef('foo:meow'), ('foo:meow', {'doc': None, 'title': None, 'defval': None, 'form': 'foo', 'base': 'meow', 'uniq': False, 'ptype': 'int'}))
self.eq(model.getPropDef('foo:meow'), ('foo:meow', {'doc': None, 'title': None, 'defval': None, 'form': 'foo', 'base': 'meow', 'uniq': False, 'ptype': 'int', 'req': False}))
self.eq(model.getPropDef('foo:meow:nonexistent'), None)
self.eq(model.getPropDef('foo:meow:nonexistent', glob=False), None)

Expand Down
Loading