diff --git a/synapse/cortex.py b/synapse/cortex.py index eca8ca68e6..784a4e9fdc 100644 --- a/synapse/cortex.py +++ b/synapse/cortex.py @@ -5943,6 +5943,8 @@ async def addCronJob(self, cdef): if not cdef.get('iden'): cdef['iden'] = s_common.guid() + cdef['created'] = s_common.now() + opts = {'user': cdef['creator'], 'view': cdef.get('view')} view = self._viewFromOpts(opts) diff --git a/synapse/lib/agenda.py b/synapse/lib/agenda.py index 8364c40108..7a4965216f 100644 --- a/synapse/lib/agenda.py +++ b/synapse/lib/agenda.py @@ -259,6 +259,7 @@ class _Appt: _synced_attrs = { 'doc', 'name', + 'created', 'enabled', 'errcount', 'nexttime', @@ -270,7 +271,7 @@ class _Appt: 'lastfinishtime', } - def __init__(self, stor, iden, recur, indx, query, creator, recs, nexttime=None, view=None): + def __init__(self, stor, iden, recur, indx, query, creator, recs, nexttime=None, view=None, created=None): self.doc = '' self.name = '' self.stor = stor @@ -282,6 +283,7 @@ def __init__(self, stor, iden, recur, indx, query, creator, recs, nexttime=None, self.recs = recs # List[ApptRec] list of the individual entries to calculate next time from self._recidxnexttime = None # index of rec who is up next self.view = view + self.created = created if self.recur and not self.recs: raise s_exc.BadTime(mesg='A recurrent appointment with no records') @@ -310,6 +312,7 @@ def getStorNode(self, form): 'doc': self.doc, 'name': self.name, 'storm': self.query, + '.created': self.created, } pnorms = {} @@ -343,6 +346,7 @@ def pack(self): 'indx': self.indx, 'query': self.query, 'creator': self.creator, + 'created': self.created, 'recs': [d.pack() for d in self.recs], 'nexttime': self.nexttime, 'startcount': self.startcount, @@ -362,6 +366,7 @@ def unpack(cls, stor, val): appt = cls(stor, val['iden'], val['recur'], val['indx'], val['query'], val['creator'], recs, nexttime=val['nexttime'], view=val.get('view')) appt.doc = val.get('doc', '') appt.name = val.get('name', '') + appt.created = val.get('created', None) appt.laststarttime = val['laststarttime'] appt.lastfinishtime = val['lastfinishtime'] appt.lastresult = val['lastresult'] @@ -592,6 +597,7 @@ async def add(self, cdef): query = cdef.get('storm') creator = cdef.get('creator') view = cdef.get('view') + created = cdef.get('created') recur = incunit is not None indx = self._next_indx @@ -633,7 +639,7 @@ async def add(self, cdef): incvals = (incvals, ) recs.extend(ApptRec(rd, incunit, v) for (rd, v) in itertools.product(reqdicts, incvals)) - appt = _Appt(self, iden, recur, indx, query, creator, recs, nexttime=nexttime, view=view) + appt = _Appt(self, iden, recur, indx, query, creator, recs, nexttime=nexttime, view=view, created=created) self._addappt(iden, appt) appt.doc = cdef.get('doc', '') diff --git a/synapse/lib/layer.py b/synapse/lib/layer.py index e082e0ba2f..203d185e0a 100644 --- a/synapse/lib/layer.py +++ b/synapse/lib/layer.py @@ -95,6 +95,7 @@ 'properties': { 'iden': {'type': 'string', 'pattern': s_config.re_iden}, 'creator': {'type': 'string', 'pattern': s_config.re_iden}, + 'created': {'type': 'integer', 'minimum': 0}, 'lockmemory': {'type': 'boolean'}, 'lmdb:growsize': {'type': 'integer'}, 'logedits': {'type': 'boolean', 'default': True}, diff --git a/synapse/lib/schemas.py b/synapse/lib/schemas.py index e840d0a125..b46a9b28a2 100644 --- a/synapse/lib/schemas.py +++ b/synapse/lib/schemas.py @@ -169,6 +169,7 @@ 'name': {'type': 'string'}, 'parent': {'type': ['string', 'null'], 'pattern': s_config.re_iden}, 'creator': {'type': 'string', 'pattern': s_config.re_iden}, + 'created': {'type': 'integer', 'minimum': 0}, 'nomerge': {'type': 'boolean'}, 'merging': {'type': 'boolean'}, 'layers': { diff --git a/synapse/lib/trigger.py b/synapse/lib/trigger.py index 461433e892..e4a5db65a1 100644 --- a/synapse/lib/trigger.py +++ b/synapse/lib/trigger.py @@ -49,6 +49,7 @@ 'storm': {'type': 'string'}, 'async': {'type': 'boolean'}, 'enabled': {'type': 'boolean'}, + 'created': {'type': 'integer', 'minimum': 0}, }, 'additionalProperties': True, 'required': ['iden', 'user', 'storm', 'enabled'], @@ -483,7 +484,7 @@ async def set(self, name, valu): ''' Set one of the dynamic elements of the trigger definition. ''' - if name not in ('enabled', 'user', 'storm', 'doc', 'name', 'async'): + if name not in ('enabled', 'user', 'storm', 'doc', 'name', 'async', 'created'): raise s_exc.BadArg(mesg=f'Invalid key name provided: {name}') if valu == self.tdef.get(name): @@ -594,6 +595,7 @@ def getStorNode(self, form): 'storm': self.tdef.get('storm'), 'enabled': self.tdef.get('enabled'), 'user': self.tdef.get('user'), + '.created': self.tdef.get('created') } tag = self.tdef.get('tag') diff --git a/synapse/lib/view.py b/synapse/lib/view.py index 64d29518c9..7281bf4d19 100644 --- a/synapse/lib/view.py +++ b/synapse/lib/view.py @@ -1387,6 +1387,7 @@ async def addTrigger(self, tdef): root = await self.core.auth.getUserByName('root') + tdef.setdefault('created', s_common.now()) tdef.setdefault('user', root.iden) tdef.setdefault('async', False) tdef.setdefault('enabled', True) diff --git a/synapse/tests/test_lib_agenda.py b/synapse/tests/test_lib_agenda.py index bca8616b0f..2ef24d4346 100644 --- a/synapse/tests/test_lib_agenda.py +++ b/synapse/tests/test_lib_agenda.py @@ -585,6 +585,7 @@ async def test_agenda_custom_view(self): jobs = await core.callStorm('return($lib.cron.list())') self.len(1, jobs) self.eq(defview.iden, jobs[0]['view']) + self.nn(jobs[0].get('created')) core.agenda._addTickOff(60) retn = await core.callStorm('return($lib.queue.get(testq).get())', opts=asfail) @@ -805,6 +806,7 @@ async def test_agenda_mirror_realtime(self): nodes = await core01.nodes('syn:cron') self.len(1, nodes) + self.nn(nodes[0].props.get('.created')) self.eq(nodes[0].props.get('name'), 'foo') self.eq(nodes[0].props.get('doc'), 'bar') diff --git a/synapse/tests/test_lib_stormtypes.py b/synapse/tests/test_lib_stormtypes.py index 87121a6ce2..7997adc0af 100644 --- a/synapse/tests/test_lib_stormtypes.py +++ b/synapse/tests/test_lib_stormtypes.py @@ -3284,6 +3284,7 @@ async def test_storm_lib_layer(self): size = info.get('totalsize') self.gt(size, 1) + self.nn(info.get('created')) # Verify we're showing actual disk usage and not just apparent self.lt(size, 1000000000) @@ -3623,6 +3624,7 @@ async def test_storm_lib_view(self): await core.stormlist('$lib.view.get().set(name, $lib.undef)') vdef = await core.callStorm('return($lib.view.get())') self.notin('name', vdef) + self.nn(vdef.get('created')) await core.stormlist('$lib.layer.get().set(name, $lib.null)') ldef = await core.callStorm('return($lib.layer.get())') @@ -4131,6 +4133,7 @@ async def test_storm_lib_trigger(self): self.true(trigdef.get('enabled')) self.nn(trigdef.get('user')) self.nn(trigdef.get('view')) + self.nn(trigdef.get('created')) self.eq(trigdef.get('storm'), '[ test:int=99 ] | spin') self.eq(trigdef.get('cond'), 'node:add') self.eq(trigdef.get('form'), 'test:str') @@ -4188,6 +4191,7 @@ async def test_storm_lib_trigger(self): self.stormIsInPrint(forkview, mesgs) self.len(1, nodes) othr = nodes[0].ndef[1] + self.nn(nodes[0].props.get('.created')) # fetch a trigger from another view self.nn(await core.callStorm(f'return($lib.trigger.get({othr}))'))