synapse 2.223.0__py311-none-any.whl → 2.225.0__py311-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse might be problematic. Click here for more details.
- synapse/axon.py +10 -5
- synapse/common.py +2 -2
- synapse/cortex.py +52 -3
- synapse/datamodel.py +1 -1
- synapse/lib/cell.py +1 -1
- synapse/lib/const.py +4 -0
- synapse/lib/layer.py +6 -6
- synapse/lib/multislabseqn.py +36 -1
- synapse/lib/nexus.py +67 -8
- synapse/lib/queue.py +4 -1
- synapse/lib/rstorm.py +2 -2
- synapse/lib/schemas.py +13 -1
- synapse/lib/slabseqn.py +28 -0
- synapse/lib/storm.py +40 -2
- synapse/lib/stormhttp.py +7 -1
- synapse/lib/stormlib/imap.py +12 -4
- synapse/lib/stormlib/task.py +0 -1
- synapse/lib/stormtypes.py +19 -1
- synapse/lib/version.py +2 -2
- synapse/models/inet.py +29 -0
- synapse/models/media.py +4 -0
- synapse/models/proj.py +3 -0
- synapse/models/risk.py +9 -0
- synapse/models/syn.py +8 -0
- synapse/tests/test_common.py +4 -0
- synapse/tests/test_cortex.py +53 -2
- synapse/tests/test_lib_agenda.py +1 -1
- synapse/tests/test_lib_cell.py +1 -1
- synapse/tests/test_lib_certdir.py +1 -1
- synapse/tests/test_lib_httpapi.py +1 -1
- synapse/tests/test_lib_layer.py +1 -1
- synapse/tests/test_lib_multislabseqn.py +22 -0
- synapse/tests/test_lib_nexus.py +42 -1
- synapse/tests/test_lib_slabseqn.py +30 -1
- synapse/tests/test_lib_storm.py +156 -1
- synapse/tests/test_lib_stormhttp.py +16 -0
- synapse/tests/test_lib_stormlib_imap.py +14 -0
- synapse/tests/test_lib_stormlib_oauth.py +1 -1
- synapse/tests/test_lib_stormsvc.py +1 -1
- synapse/tests/test_lib_stormtypes.py +12 -0
- synapse/tests/test_lib_trigger.py +1 -1
- synapse/tests/test_model_inet.py +29 -0
- synapse/tests/test_model_media.py +4 -1
- synapse/tests/test_model_proj.py +3 -1
- synapse/tests/test_model_risk.py +12 -0
- synapse/tests/test_model_syn.py +54 -2
- synapse/tests/{test_tools_axon2axon.py → test_tools_axon_copy.py} +4 -4
- synapse/tests/{test_tools_pullfile.py → test_tools_axon_get.py} +4 -4
- synapse/tests/{test_tools_pushfile.py → test_tools_axon_put.py} +7 -7
- synapse/tests/{test_tools_csvtool.py → test_tools_cortex_csv.py} +12 -3
- synapse/tests/{test_tools_feed.py → test_tools_cortex_feed.py} +2 -2
- synapse/tests/{test_tools_apikey.py → test_tools_service_apikey.py} +1 -4
- synapse/tests/{test_tools_backup.py → test_tools_service_backup.py} +5 -5
- synapse/tests/{test_tools_demote.py → test_tools_service_demote.py} +1 -1
- synapse/tests/{test_tools_healthcheck.py → test_tools_service_healthcheck.py} +1 -1
- synapse/tests/{test_tools_livebackup.py → test_tools_service_livebackup.py} +1 -1
- synapse/tests/{test_tools_modrole.py → test_tools_service_modrole.py} +1 -1
- synapse/tests/{test_tools_moduser.py → test_tools_service_moduser.py} +1 -1
- synapse/tests/{test_tools_promote.py → test_tools_service_promote.py} +1 -1
- synapse/tests/{test_tools_reload.py → test_tools_service_reload.py} +1 -1
- synapse/tests/{test_tools_shutdown.py → test_tools_service_shutdown.py} +1 -1
- synapse/tests/{test_tools_snapshot.py → test_tools_service_snapshot.py} +1 -1
- synapse/tests/{test_tools_storm.py → test_tools_storm_cli.py} +1 -1
- synapse/tests/{test_tools_pkgs_gendocs.py → test_tools_storm_pkg_doc.py} +12 -3
- synapse/tests/{test_tools_genpkg.py → test_tools_storm_pkg_gen.py} +1 -1
- synapse/tests/{test_tools_autodoc.py → test_tools_utils_autodoc.py} +1 -1
- synapse/tests/test_tools_utils_changelog.py +454 -0
- synapse/tests/{test_tools_easycert.py → test_tools_utils_easycert.py} +48 -46
- synapse/tests/{test_tools_guid.py → test_tools_utils_guid.py} +3 -3
- synapse/tests/{test_tools_json2mpk.py → test_tools_utils_json2mpk.py} +3 -3
- synapse/tests/{test_tools_rstorm.py → test_tools_utils_rstorm.py} +6 -1
- synapse/tests/utils.py +3 -1
- synapse/tools/apikey.py +4 -83
- synapse/tools/autodoc.py +3 -1031
- synapse/tools/axon/copy.py +44 -0
- synapse/tools/axon/get.py +64 -0
- synapse/tools/axon/put.py +122 -0
- synapse/tools/axon2axon.py +3 -36
- synapse/tools/backup.py +6 -176
- synapse/tools/changelog.py +3 -1098
- synapse/tools/cortex/csv.py +236 -0
- synapse/tools/cortex/feed.py +151 -0
- synapse/tools/csvtool.py +3 -227
- synapse/tools/demote.py +4 -40
- synapse/tools/docker/validate.py +3 -3
- synapse/tools/easycert.py +4 -129
- synapse/tools/feed.py +3 -140
- synapse/tools/genpkg.py +3 -307
- synapse/tools/guid.py +7 -6
- synapse/tools/healthcheck.py +3 -101
- synapse/tools/json2mpk.py +6 -38
- synapse/tools/livebackup.py +4 -27
- synapse/tools/modrole.py +3 -108
- synapse/tools/moduser.py +3 -179
- synapse/tools/pkgs/gendocs.py +3 -164
- synapse/tools/promote.py +4 -41
- synapse/tools/pullfile.py +3 -56
- synapse/tools/pushfile.py +3 -114
- synapse/tools/reload.py +4 -61
- synapse/tools/rstorm.py +3 -26
- synapse/tools/service/__init__.py +0 -0
- synapse/tools/service/apikey.py +90 -0
- synapse/tools/service/backup.py +181 -0
- synapse/tools/service/demote.py +47 -0
- synapse/tools/service/healthcheck.py +109 -0
- synapse/tools/service/livebackup.py +34 -0
- synapse/tools/service/modrole.py +116 -0
- synapse/tools/service/moduser.py +184 -0
- synapse/tools/service/promote.py +48 -0
- synapse/tools/service/reload.py +68 -0
- synapse/tools/service/shutdown.py +51 -0
- synapse/tools/service/snapshot.py +64 -0
- synapse/tools/shutdown.py +5 -45
- synapse/tools/snapshot.py +4 -57
- synapse/tools/storm/__init__.py +0 -0
- synapse/tools/storm/__main__.py +5 -0
- synapse/tools/{storm.py → storm/_cli.py} +0 -3
- synapse/tools/storm/pkg/__init__.py +0 -0
- synapse/tools/{pkgs/pandoc_filter.py → storm/pkg/_pandoc_filter.py} +1 -1
- synapse/tools/storm/pkg/doc.py +176 -0
- synapse/tools/storm/pkg/gen.py +315 -0
- synapse/tools/utils/__init__.py +0 -0
- synapse/tools/utils/autodoc.py +1040 -0
- synapse/tools/utils/changelog.py +1124 -0
- synapse/tools/utils/easycert.py +136 -0
- synapse/tools/utils/guid.py +11 -0
- synapse/tools/utils/json2mpk.py +46 -0
- synapse/tools/utils/rstorm.py +35 -0
- {synapse-2.223.0.dist-info → synapse-2.225.0.dist-info}/METADATA +1 -1
- {synapse-2.223.0.dist-info → synapse-2.225.0.dist-info}/RECORD +134 -105
- synapse/tests/test_tools_changelog.py +0 -196
- /synapse/tests/{test_tools_axon.py → test_tools_axon_dump_load.py} +0 -0
- {synapse-2.223.0.dist-info → synapse-2.225.0.dist-info}/WHEEL +0 -0
- {synapse-2.223.0.dist-info → synapse-2.225.0.dist-info}/licenses/LICENSE +0 -0
- {synapse-2.223.0.dist-info → synapse-2.225.0.dist-info}/top_level.txt +0 -0
synapse/axon.py
CHANGED
|
@@ -1651,8 +1651,9 @@ class Axon(s_cell.Cell):
|
|
|
1651
1651
|
filename=field.get('filename'),
|
|
1652
1652
|
content_transfer_encoding=field.get('content_transfer_encoding'))
|
|
1653
1653
|
|
|
1654
|
-
async with sess.request(method, url, headers=headers, params=params,
|
|
1655
|
-
|
|
1654
|
+
async with sess.request(method, url, headers=headers, params=params, data=data, ssl=ssl,
|
|
1655
|
+
max_line_size=s_const.MAX_LINE_SIZE,
|
|
1656
|
+
max_field_size=s_const.MAX_FIELD_SIZE) as resp:
|
|
1656
1657
|
info = {
|
|
1657
1658
|
'ok': True,
|
|
1658
1659
|
'url': str(resp.url),
|
|
@@ -1698,8 +1699,10 @@ class Axon(s_cell.Cell):
|
|
|
1698
1699
|
async with aiohttp.ClientSession(connector=connector, timeout=atimeout) as sess:
|
|
1699
1700
|
try:
|
|
1700
1701
|
await self._reqHas(sha256)
|
|
1701
|
-
async with sess.request(method, url, headers=headers, params=params,
|
|
1702
|
-
data=self.get(sha256),
|
|
1702
|
+
async with sess.request(method, url, headers=headers, params=params, ssl=ssl,
|
|
1703
|
+
data=self.get(sha256),
|
|
1704
|
+
max_line_size=s_const.MAX_LINE_SIZE,
|
|
1705
|
+
max_field_size=s_const.MAX_FIELD_SIZE) as resp:
|
|
1703
1706
|
|
|
1704
1707
|
info = {
|
|
1705
1708
|
'ok': True,
|
|
@@ -1827,7 +1830,9 @@ class Axon(s_cell.Cell):
|
|
|
1827
1830
|
async with aiohttp.ClientSession(connector=connector, timeout=atimeout) as sess:
|
|
1828
1831
|
|
|
1829
1832
|
try:
|
|
1830
|
-
async with sess.request(method, url, headers=headers, params=params, json=json, data=body, ssl=ssl
|
|
1833
|
+
async with sess.request(method, url, headers=headers, params=params, json=json, data=body, ssl=ssl,
|
|
1834
|
+
max_line_size=s_const.MAX_LINE_SIZE,
|
|
1835
|
+
max_field_size=s_const.MAX_FIELD_SIZE) as resp:
|
|
1831
1836
|
|
|
1832
1837
|
info = self._flatten_clientresponse(resp)
|
|
1833
1838
|
|
synapse/common.py
CHANGED
|
@@ -144,7 +144,7 @@ def flatten(item):
|
|
|
144
144
|
item: The python primitive object to normalize.
|
|
145
145
|
|
|
146
146
|
Notes:
|
|
147
|
-
Only None, bool, int, bytes, strings, lists, tuples and dictionaries are acceptable input.
|
|
147
|
+
Only None, bool, int, bytes, strings, floats, lists, tuples and dictionaries are acceptable input.
|
|
148
148
|
List objects will be converted to tuples.
|
|
149
149
|
Dictionary objects must have keys which can be sorted.
|
|
150
150
|
|
|
@@ -155,7 +155,7 @@ def flatten(item):
|
|
|
155
155
|
if item is None:
|
|
156
156
|
return None
|
|
157
157
|
|
|
158
|
-
if isinstance(item, (str, int, bytes)):
|
|
158
|
+
if isinstance(item, (str, int, bytes, float)):
|
|
159
159
|
return item
|
|
160
160
|
|
|
161
161
|
if isinstance(item, (tuple, list)):
|
synapse/cortex.py
CHANGED
|
@@ -464,6 +464,15 @@ class CoreApi(s_cell.CellApi):
|
|
|
464
464
|
'''
|
|
465
465
|
return await self.cell.getTypeNorm(name, valu, typeopts=typeopts)
|
|
466
466
|
|
|
467
|
+
async def addType(self, typename, basetype, typeopts, typeinfo):
|
|
468
|
+
'''
|
|
469
|
+
Add an extended type to the data model.
|
|
470
|
+
|
|
471
|
+
Extended types must begin with _
|
|
472
|
+
'''
|
|
473
|
+
self.user.confirm(('model', 'type', 'add', typename))
|
|
474
|
+
return await self.cell.addType(typename, basetype, typeopts, typeinfo)
|
|
475
|
+
|
|
467
476
|
async def addForm(self, formname, basetype, typeopts, typeinfo):
|
|
468
477
|
'''
|
|
469
478
|
Add an extended form to the data model.
|
|
@@ -535,6 +544,15 @@ class CoreApi(s_cell.CellApi):
|
|
|
535
544
|
self.user.confirm(('model', 'tagprop', 'del'))
|
|
536
545
|
return await self.cell.delTagProp(name)
|
|
537
546
|
|
|
547
|
+
async def addEdge(self, edge, edgeinfo):
|
|
548
|
+
'''
|
|
549
|
+
Add an extended edge definition to the data model.
|
|
550
|
+
|
|
551
|
+
Extended edge definitions must use a verb which begins with _
|
|
552
|
+
'''
|
|
553
|
+
self.user.confirm(('model', 'edge', 'add'))
|
|
554
|
+
return await self.cell.addEdge(edge, edgeinfo)
|
|
555
|
+
|
|
538
556
|
async def addStormPkg(self, pkgdef, verify=False):
|
|
539
557
|
self.user.confirm(('pkg', 'add'))
|
|
540
558
|
return await self.cell.addStormPkg(pkgdef, verify=verify)
|
|
@@ -1440,6 +1458,11 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
1440
1458
|
{'perm': ('model', 'univ', 'del'), 'gate': 'cortex',
|
|
1441
1459
|
'desc': 'Controls access to deleting extended model universal properties and values.'},
|
|
1442
1460
|
|
|
1461
|
+
{'perm': ('model', 'edge', 'add'), 'gate': 'cortex',
|
|
1462
|
+
'desc': 'Controls access to adding extended model edges.'},
|
|
1463
|
+
{'perm': ('model', 'edge', 'del'), 'gate': 'cortex',
|
|
1464
|
+
'desc': 'Controls access to deleting extended model edges.'},
|
|
1465
|
+
|
|
1443
1466
|
{'perm': ('node',), 'gate': 'layer',
|
|
1444
1467
|
'desc': 'Controls all node edits in a layer.'},
|
|
1445
1468
|
{'perm': ('node', 'add'), 'gate': 'layer',
|
|
@@ -2568,6 +2591,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2568
2591
|
ctor.pkgname = cdef.get('pkgname')
|
|
2569
2592
|
ctor.svciden = cdef.get('cmdconf', {}).get('svciden', '')
|
|
2570
2593
|
ctor.forms = cdef.get('forms', {})
|
|
2594
|
+
ctor.deprecated = cdef.get('deprecated', {})
|
|
2571
2595
|
|
|
2572
2596
|
def getStorNode(form):
|
|
2573
2597
|
ndef = (form.name, form.type.norm(cdef.get('name'))[0])
|
|
@@ -2596,6 +2620,18 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2596
2620
|
if ctor.pkgname:
|
|
2597
2621
|
props['package'] = ctor.pkgname
|
|
2598
2622
|
|
|
2623
|
+
if ctor.deprecated:
|
|
2624
|
+
props['deprecated'] = True
|
|
2625
|
+
|
|
2626
|
+
if (eolvers := ctor.deprecated.get('eolvers')) is not None:
|
|
2627
|
+
props['deprecated:version'] = eolvers
|
|
2628
|
+
|
|
2629
|
+
if (eoldate := ctor.deprecated.get('eoldate')) is not None:
|
|
2630
|
+
props['deprecated:date'] = eoldate
|
|
2631
|
+
|
|
2632
|
+
if (mesg := ctor.deprecated.get('mesg')) is not None:
|
|
2633
|
+
props['deprecated:mesg'] = mesg
|
|
2634
|
+
|
|
2599
2635
|
pnorms = {}
|
|
2600
2636
|
for prop, valu in props.items():
|
|
2601
2637
|
formprop = form.props.get(prop)
|
|
@@ -3662,6 +3698,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3662
3698
|
|
|
3663
3699
|
return True
|
|
3664
3700
|
|
|
3701
|
+
@s_cell.from_leader
|
|
3665
3702
|
async def addUnivProp(self, name, tdef, info):
|
|
3666
3703
|
if not isinstance(tdef, tuple):
|
|
3667
3704
|
mesg = 'Universal property type definitions should be a tuple.'
|
|
@@ -3676,6 +3713,8 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3676
3713
|
mesg = 'ext univ name must start with "_"'
|
|
3677
3714
|
raise s_exc.BadPropDef(name=name, mesg=mesg)
|
|
3678
3715
|
|
|
3716
|
+
self.model.getTypeClone(tdef)
|
|
3717
|
+
|
|
3679
3718
|
base = '.' + name
|
|
3680
3719
|
if base in self.model.props:
|
|
3681
3720
|
raise s_exc.DupPropName(mesg=f'Cannot add duplicate universal property {base}',
|
|
@@ -3697,6 +3736,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3697
3736
|
if univ:
|
|
3698
3737
|
await self.feedBeholder('model:univ:add', univ.pack())
|
|
3699
3738
|
|
|
3739
|
+
@s_cell.from_leader
|
|
3700
3740
|
async def addForm(self, formname, basetype, typeopts, typeinfo):
|
|
3701
3741
|
if not isinstance(typeopts, dict):
|
|
3702
3742
|
mesg = 'Form type options should be a dict.'
|
|
@@ -3718,6 +3758,8 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3718
3758
|
mesg = f'Type already exists: {formname}'
|
|
3719
3759
|
raise s_exc.DupTypeName.init(formname)
|
|
3720
3760
|
|
|
3761
|
+
self.model.getTypeClone((basetype, typeopts))
|
|
3762
|
+
|
|
3721
3763
|
return await self._push('model:form:add', formname, basetype, typeopts, typeinfo)
|
|
3722
3764
|
|
|
3723
3765
|
@s_nexus.Pusher.onPush('model:form:add')
|
|
@@ -3772,6 +3814,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3772
3814
|
await self.fire('core:extmodel:change', form=formname, act='del', type='form')
|
|
3773
3815
|
await self.feedBeholder('model:form:del', {'form': formname})
|
|
3774
3816
|
|
|
3817
|
+
@s_cell.from_leader
|
|
3775
3818
|
async def addType(self, typename, basetype, typeopts, typeinfo):
|
|
3776
3819
|
if not isinstance(typeopts, dict):
|
|
3777
3820
|
mesg = 'Type options should be a dict.'
|
|
@@ -3840,6 +3883,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3840
3883
|
await self.fire('core:extmodel:change', name=typename, act='del', type='type')
|
|
3841
3884
|
await self.feedBeholder('model:type:del', {'type': typename})
|
|
3842
3885
|
|
|
3886
|
+
@s_cell.from_leader
|
|
3843
3887
|
async def addFormProp(self, form, prop, tdef, info):
|
|
3844
3888
|
if not isinstance(tdef, tuple):
|
|
3845
3889
|
mesg = 'Form property type definitions should be a tuple.'
|
|
@@ -3858,6 +3902,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3858
3902
|
if _form.prop(prop):
|
|
3859
3903
|
raise s_exc.DupPropName(mesg=f'Cannot add duplicate form prop {form} {prop}',
|
|
3860
3904
|
form=form, prop=prop)
|
|
3905
|
+
|
|
3906
|
+
self.model.getTypeClone(tdef)
|
|
3907
|
+
|
|
3861
3908
|
await self._push('model:prop:add', form, prop, tdef, info)
|
|
3862
3909
|
|
|
3863
3910
|
@s_nexus.Pusher.onPush('model:prop:add')
|
|
@@ -4039,6 +4086,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
4039
4086
|
await self.fire('core:extmodel:change', name=prop, act='del', type='univ')
|
|
4040
4087
|
await self.feedBeholder('model:univ:del', {'prop': univname})
|
|
4041
4088
|
|
|
4089
|
+
@s_cell.from_leader
|
|
4042
4090
|
async def addTagProp(self, name, tdef, info):
|
|
4043
4091
|
if not isinstance(tdef, tuple):
|
|
4044
4092
|
mesg = 'Tag property type definitions should be a tuple.'
|
|
@@ -4051,6 +4099,8 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
4051
4099
|
if self.exttagprops.get(name) is not None:
|
|
4052
4100
|
raise s_exc.DupPropName(name=name)
|
|
4053
4101
|
|
|
4102
|
+
self.model.getTypeClone(tdef)
|
|
4103
|
+
|
|
4054
4104
|
return await self._push('model:tagprop:add', name, tdef, info)
|
|
4055
4105
|
|
|
4056
4106
|
@s_nexus.Pusher.onPush('model:tagprop:add')
|
|
@@ -4088,6 +4138,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
4088
4138
|
await self.fire('core:tagprop:change', name=name, act='del')
|
|
4089
4139
|
await self.feedBeholder('model:tagprop:del', {'tagprop': name})
|
|
4090
4140
|
|
|
4141
|
+
@s_cell.from_leader
|
|
4091
4142
|
async def addEdge(self, edge, edgeinfo):
|
|
4092
4143
|
if not isinstance(edgeinfo, dict):
|
|
4093
4144
|
mesg = 'Edge info should be a dict.'
|
|
@@ -4667,6 +4718,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
4667
4718
|
s_stormlib_macro,
|
|
4668
4719
|
s_stormlib_model,
|
|
4669
4720
|
s_stormlib_pkg,
|
|
4721
|
+
s_stormlib_task,
|
|
4670
4722
|
s_stormlib_vault,
|
|
4671
4723
|
]
|
|
4672
4724
|
|
|
@@ -4674,9 +4726,6 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
4674
4726
|
for cdef in cmod.stormcmds:
|
|
4675
4727
|
await self._trySetStormCmd(cdef.get('name'), cdef)
|
|
4676
4728
|
|
|
4677
|
-
for cdef in s_stormlib_task.stormcmds:
|
|
4678
|
-
await self._trySetStormCmd(cdef.get('name'), cdef)
|
|
4679
|
-
|
|
4680
4729
|
async def _initPureStormCmds(self):
|
|
4681
4730
|
oldcmds = []
|
|
4682
4731
|
for name, cdef in self.cmddefs.items():
|
synapse/datamodel.py
CHANGED
synapse/lib/cell.py
CHANGED
synapse/lib/const.py
CHANGED
synapse/lib/layer.py
CHANGED
|
@@ -127,7 +127,7 @@ class LayerApi(s_cell.CellApi):
|
|
|
127
127
|
Scan the full layer and yield artificial nodeedit sets.
|
|
128
128
|
'''
|
|
129
129
|
|
|
130
|
-
if not self.allowed(self.liftperm):
|
|
130
|
+
if not await self.allowed(self.liftperm):
|
|
131
131
|
await self._reqUserAllowed(self.readperm)
|
|
132
132
|
async for item in self.layr.iterLayerNodeEdits():
|
|
133
133
|
yield item
|
|
@@ -167,14 +167,14 @@ class LayerApi(s_cell.CellApi):
|
|
|
167
167
|
|
|
168
168
|
Once caught up with storage, yield them in realtime.
|
|
169
169
|
'''
|
|
170
|
-
if not self.allowed(self.liftperm):
|
|
170
|
+
if not await self.allowed(self.liftperm):
|
|
171
171
|
await self._reqUserAllowed(self.readperm)
|
|
172
172
|
async for item in self.layr.syncNodeEdits(offs, wait=wait, reverse=reverse):
|
|
173
173
|
yield item
|
|
174
174
|
await asyncio.sleep(0)
|
|
175
175
|
|
|
176
176
|
async def syncNodeEdits2(self, offs, wait=True):
|
|
177
|
-
if not self.allowed(self.liftperm):
|
|
177
|
+
if not await self.allowed(self.liftperm):
|
|
178
178
|
await self._reqUserAllowed(self.readperm)
|
|
179
179
|
async for item in self.layr.syncNodeEdits2(offs, wait=wait):
|
|
180
180
|
yield item
|
|
@@ -184,7 +184,7 @@ class LayerApi(s_cell.CellApi):
|
|
|
184
184
|
'''
|
|
185
185
|
Returns what will be the *next* nodeedit log index.
|
|
186
186
|
'''
|
|
187
|
-
if not self.allowed(self.liftperm):
|
|
187
|
+
if not await self.allowed(self.liftperm):
|
|
188
188
|
await self._reqUserAllowed(self.readperm)
|
|
189
189
|
return await self.layr.getEditIndx()
|
|
190
190
|
|
|
@@ -192,12 +192,12 @@ class LayerApi(s_cell.CellApi):
|
|
|
192
192
|
'''
|
|
193
193
|
Return the total number of (edits, meta) pairs in the layer changelog.
|
|
194
194
|
'''
|
|
195
|
-
if not self.allowed(self.liftperm):
|
|
195
|
+
if not await self.allowed(self.liftperm):
|
|
196
196
|
await self._reqUserAllowed(self.readperm)
|
|
197
197
|
return await self.layr.getEditSize()
|
|
198
198
|
|
|
199
199
|
async def getIden(self):
|
|
200
|
-
if not self.allowed(self.liftperm):
|
|
200
|
+
if not await self.allowed(self.liftperm):
|
|
201
201
|
await self._reqUserAllowed(self.readperm)
|
|
202
202
|
return self.layr.iden
|
|
203
203
|
|
synapse/lib/multislabseqn.py
CHANGED
|
@@ -353,7 +353,6 @@ class MultiSlabSeqn(s_base.Base):
|
|
|
353
353
|
else:
|
|
354
354
|
indx = self.indx
|
|
355
355
|
|
|
356
|
-
assert self.tailseqn
|
|
357
356
|
retn = self.tailseqn.add(item, indx=indx)
|
|
358
357
|
|
|
359
358
|
if advances:
|
|
@@ -363,6 +362,42 @@ class MultiSlabSeqn(s_base.Base):
|
|
|
363
362
|
|
|
364
363
|
return retn
|
|
365
364
|
|
|
365
|
+
async def addWithPackRetn(self, item, indx=None):
|
|
366
|
+
'''
|
|
367
|
+
Add a single item to the sequence, returning the offset and packed item.
|
|
368
|
+
'''
|
|
369
|
+
advances = True
|
|
370
|
+
|
|
371
|
+
if indx is not None:
|
|
372
|
+
if indx < self.firstindx:
|
|
373
|
+
raise s_exc.BadIndxValu(mesg=f'indx lower than first index in sequence {self.firstindx}')
|
|
374
|
+
|
|
375
|
+
if indx < self._ranges[-1]:
|
|
376
|
+
ridx = self._getRangeIndx(indx)
|
|
377
|
+
assert ridx is not None
|
|
378
|
+
|
|
379
|
+
async with self._getSeqn(ridx) as seqn:
|
|
380
|
+
retn = seqn.addWithPackRetn(item, indx=indx)
|
|
381
|
+
|
|
382
|
+
return retn
|
|
383
|
+
|
|
384
|
+
if indx >= self.indx:
|
|
385
|
+
self.indx = indx
|
|
386
|
+
else:
|
|
387
|
+
advances = False
|
|
388
|
+
else:
|
|
389
|
+
indx = self.indx
|
|
390
|
+
|
|
391
|
+
assert self.tailseqn
|
|
392
|
+
retn = self.tailseqn.addWithPackRetn(item, indx=indx)
|
|
393
|
+
|
|
394
|
+
if advances:
|
|
395
|
+
self.indx += 1
|
|
396
|
+
|
|
397
|
+
self._wake_waiters()
|
|
398
|
+
|
|
399
|
+
return retn
|
|
400
|
+
|
|
366
401
|
async def last(self) -> Optional[Tuple[int, Any]]:
|
|
367
402
|
ridx = self._getRangeIndx(self.indx - 1)
|
|
368
403
|
if ridx is None:
|
synapse/lib/nexus.py
CHANGED
|
@@ -12,6 +12,9 @@ import synapse.common as s_common
|
|
|
12
12
|
import synapse.telepath as s_telepath
|
|
13
13
|
|
|
14
14
|
import synapse.lib.base as s_base
|
|
15
|
+
import synapse.lib.scope as s_scope
|
|
16
|
+
import synapse.lib.queue as s_queue
|
|
17
|
+
import synapse.lib.msgpack as s_msgpack
|
|
15
18
|
|
|
16
19
|
logger = logging.getLogger(__name__)
|
|
17
20
|
|
|
@@ -20,6 +23,9 @@ leaderversion = 'Leader is a higher version than we are.'
|
|
|
20
23
|
# As a mirror follower, amount of time before giving up on a write request
|
|
21
24
|
FOLLOWER_WRITE_WAIT_S = 30.0
|
|
22
25
|
|
|
26
|
+
WINDOW_MAXSIZE = 10_000
|
|
27
|
+
YIELD_PREFIX = b'\x92\xa8t2:yield\x81\xa4retn\x92\xc3\x92'
|
|
28
|
+
|
|
23
29
|
class RegMethType(type):
|
|
24
30
|
'''
|
|
25
31
|
Metaclass that collects all methods in class with _regme prop into a class member called _regclstupls
|
|
@@ -99,6 +105,8 @@ class NexsRoot(s_base.Base):
|
|
|
99
105
|
self._mirready = asyncio.Event() # for testing
|
|
100
106
|
|
|
101
107
|
self._mirrors: List[ChangeDist] = []
|
|
108
|
+
self._linkmirrors: List[s_queue.Window] = []
|
|
109
|
+
|
|
102
110
|
self._nexskids: Dict[str, 'Pusher'] = {}
|
|
103
111
|
|
|
104
112
|
# Used to match pending follower write requests with the responses arriving on the log
|
|
@@ -134,6 +142,11 @@ class NexsRoot(s_base.Base):
|
|
|
134
142
|
self.nexslog.setIndex(maxindx)
|
|
135
143
|
|
|
136
144
|
async def fini():
|
|
145
|
+
for wind in self._linkmirrors:
|
|
146
|
+
await wind.fini()
|
|
147
|
+
|
|
148
|
+
for dist in self._mirrors:
|
|
149
|
+
await dist.fini()
|
|
137
150
|
|
|
138
151
|
for futu in self._futures.values(): # pragma: no cover
|
|
139
152
|
futu.cancel()
|
|
@@ -389,8 +402,16 @@ class NexsRoot(s_base.Base):
|
|
|
389
402
|
async def _eat(self, item, indx=None):
|
|
390
403
|
|
|
391
404
|
if self.donexslog:
|
|
392
|
-
saveindx = await self.nexslog.
|
|
393
|
-
|
|
405
|
+
saveindx, packitem = await self.nexslog.addWithPackRetn(item, indx=indx)
|
|
406
|
+
|
|
407
|
+
if self._linkmirrors:
|
|
408
|
+
tupl = (saveindx, YIELD_PREFIX + s_msgpack.en(saveindx) + packitem)
|
|
409
|
+
for wind in tuple(self._linkmirrors):
|
|
410
|
+
await wind.put(tupl)
|
|
411
|
+
|
|
412
|
+
if self._mirrors:
|
|
413
|
+
for dist in tuple(self._mirrors):
|
|
414
|
+
dist.update()
|
|
394
415
|
|
|
395
416
|
else:
|
|
396
417
|
saveindx = self.nexshot.get('nexs:indx')
|
|
@@ -415,7 +436,15 @@ class NexsRoot(s_base.Base):
|
|
|
415
436
|
|
|
416
437
|
async def iter(self, offs: int, tellready=False, wait=True) -> AsyncIterator[Any]:
|
|
417
438
|
'''
|
|
418
|
-
Returns an iterator of change entries in the log
|
|
439
|
+
Returns an iterator of change entries in the log.
|
|
440
|
+
|
|
441
|
+
Notes:
|
|
442
|
+
If this method is being called in the context of a Telepath call,
|
|
443
|
+
it will directly send messages to the scope "link" object when it
|
|
444
|
+
has caught up to the realtime change window; instead of yielding
|
|
445
|
+
them as a generator. This is an optimization to avoid duplication
|
|
446
|
+
of msgpack'ing the same object over and over again as the number
|
|
447
|
+
of mirrors increases.
|
|
419
448
|
'''
|
|
420
449
|
if not self.donexslog:
|
|
421
450
|
return
|
|
@@ -437,11 +466,41 @@ class NexsRoot(s_base.Base):
|
|
|
437
466
|
if not wait:
|
|
438
467
|
return
|
|
439
468
|
|
|
440
|
-
|
|
441
|
-
async
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
469
|
+
if (link := s_scope.get('link')) is None:
|
|
470
|
+
async with self.getChangeDist(maxoffs) as dist:
|
|
471
|
+
async for item in dist:
|
|
472
|
+
yield item
|
|
473
|
+
|
|
474
|
+
else:
|
|
475
|
+
async with self.getMirrorWindow() as wind:
|
|
476
|
+
|
|
477
|
+
# Ensure we are caught up after grabbing a window
|
|
478
|
+
sync = True
|
|
479
|
+
|
|
480
|
+
async for item in self.nexslog.iter(maxoffs):
|
|
481
|
+
maxoffs = item[0] + 1
|
|
482
|
+
yield item
|
|
483
|
+
|
|
484
|
+
async for offs, item in wind:
|
|
485
|
+
if sync:
|
|
486
|
+
if offs < maxoffs:
|
|
487
|
+
continue
|
|
488
|
+
sync = False
|
|
489
|
+
|
|
490
|
+
await link.send(item)
|
|
491
|
+
|
|
492
|
+
@contextlib.asynccontextmanager
|
|
493
|
+
async def getMirrorWindow(self):
|
|
494
|
+
async with await s_queue.Window.anit(maxsize=WINDOW_MAXSIZE, clearonfini=True) as wind:
|
|
495
|
+
|
|
496
|
+
async def fini():
|
|
497
|
+
self._linkmirrors.remove(wind)
|
|
498
|
+
|
|
499
|
+
wind.onfini(fini)
|
|
500
|
+
|
|
501
|
+
self._linkmirrors.append(wind)
|
|
502
|
+
|
|
503
|
+
yield wind
|
|
445
504
|
|
|
446
505
|
@contextlib.asynccontextmanager
|
|
447
506
|
async def getChangeDist(self, offs: int) -> AsyncIterator[ChangeDist]:
|
synapse/lib/queue.py
CHANGED
|
@@ -118,14 +118,17 @@ class Window(s_base.Base):
|
|
|
118
118
|
its maxsize, it will be fini()d. On fini(), the Window will continue to
|
|
119
119
|
yield results until empty and then return.
|
|
120
120
|
'''
|
|
121
|
-
async def __anit__(self, maxsize=None):
|
|
121
|
+
async def __anit__(self, maxsize=None, clearonfini=False):
|
|
122
122
|
await s_base.Base.__anit__(self)
|
|
123
123
|
self.maxsize = maxsize
|
|
124
124
|
self.event = asyncio.Event()
|
|
125
125
|
|
|
126
126
|
self.linklist = collections.deque()
|
|
127
|
+
self.clearonfini = clearonfini
|
|
127
128
|
|
|
128
129
|
async def fini():
|
|
130
|
+
if self.clearonfini:
|
|
131
|
+
self.linklist.clear()
|
|
129
132
|
self.event.set()
|
|
130
133
|
|
|
131
134
|
self.onfini(fini)
|
synapse/lib/rstorm.py
CHANGED
|
@@ -25,8 +25,8 @@ import synapse.lib.stormhttp as s_stormhttp
|
|
|
25
25
|
|
|
26
26
|
import synapse.cmds.cortex as s_cmds_cortex
|
|
27
27
|
|
|
28
|
-
import synapse.tools.storm as s_storm
|
|
29
|
-
import synapse.tools.
|
|
28
|
+
import synapse.tools.storm._cli as s_storm
|
|
29
|
+
import synapse.tools.storm.pkg.gen as s_genpkg
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
re_directive = regex.compile(r'^\.\.\s(shell.*|storm.*|[^:])::(?:\s(.*)$|$)')
|
synapse/lib/schemas.py
CHANGED
|
@@ -393,7 +393,6 @@ _changelogTypes = {'migration': 'Automatic Migrations',
|
|
|
393
393
|
'note': 'Notes',
|
|
394
394
|
'doc': 'Improved documentation',
|
|
395
395
|
'deprecation': 'Deprecations'}
|
|
396
|
-
|
|
397
396
|
_changelogSchema = {
|
|
398
397
|
'type': 'object',
|
|
399
398
|
'properties': {
|
|
@@ -405,6 +404,10 @@ _changelogSchema = {
|
|
|
405
404
|
'type': 'string',
|
|
406
405
|
'minLength': 1,
|
|
407
406
|
},
|
|
407
|
+
'desc:literal': {
|
|
408
|
+
'type': 'boolean',
|
|
409
|
+
'default': False,
|
|
410
|
+
},
|
|
408
411
|
'prs': {
|
|
409
412
|
'type': 'array',
|
|
410
413
|
'items': {
|
|
@@ -948,12 +951,20 @@ _reqValidPkgdefSchema = {
|
|
|
948
951
|
'type': ['array', 'null'],
|
|
949
952
|
'items': {'$ref': '#/definitions/cmdinput'},
|
|
950
953
|
},
|
|
954
|
+
'cmdconf': {
|
|
955
|
+
'type': 'object',
|
|
956
|
+
'properties': {
|
|
957
|
+
'svciden': {'type': 'string', 'pattern': s_config.re_iden},
|
|
958
|
+
},
|
|
959
|
+
'additionalProperties': True,
|
|
960
|
+
},
|
|
951
961
|
'storm': {'type': 'string'},
|
|
952
962
|
'forms': {'$ref': '#/definitions/cmdformhints'},
|
|
953
963
|
'perms': {'type': 'array',
|
|
954
964
|
'items': {'type': 'array',
|
|
955
965
|
'items': {'type': 'string'}},
|
|
956
966
|
},
|
|
967
|
+
'deprecated': {'$ref': '#/definitions/deprecatedItem'},
|
|
957
968
|
},
|
|
958
969
|
'additionalProperties': True,
|
|
959
970
|
'required': ['name', 'storm']
|
|
@@ -980,6 +991,7 @@ _reqValidPkgdefSchema = {
|
|
|
980
991
|
'type': 'string',
|
|
981
992
|
'enum': s_msgpack.deepcopy(datamodel_basetypes),
|
|
982
993
|
},
|
|
994
|
+
'deprecated': {'$ref': '#/definitions/deprecatedItem'},
|
|
983
995
|
},
|
|
984
996
|
}
|
|
985
997
|
],
|
synapse/lib/slabseqn.py
CHANGED
|
@@ -87,6 +87,34 @@ class SlabSeqn:
|
|
|
87
87
|
|
|
88
88
|
return indx
|
|
89
89
|
|
|
90
|
+
def addWithPackRetn(self, item, indx=None):
|
|
91
|
+
'''
|
|
92
|
+
Add a single item to the sequence, returning the offset and packed item.
|
|
93
|
+
'''
|
|
94
|
+
packitem = s_msgpack.en(item)
|
|
95
|
+
if indx is not None:
|
|
96
|
+
if indx >= self.indx:
|
|
97
|
+
self.slab.put(s_common.int64en(indx), packitem, append=True, db=self.db)
|
|
98
|
+
self.indx = indx + 1
|
|
99
|
+
self.size += 1
|
|
100
|
+
self._wake_waiters()
|
|
101
|
+
return indx, packitem
|
|
102
|
+
|
|
103
|
+
oldv = self.slab.replace(s_common.int64en(indx), packitem, db=self.db)
|
|
104
|
+
if oldv is None:
|
|
105
|
+
self.size += 1
|
|
106
|
+
return indx, packitem
|
|
107
|
+
|
|
108
|
+
indx = self.indx
|
|
109
|
+
self.slab.put(s_common.int64en(indx), packitem, append=True, db=self.db)
|
|
110
|
+
|
|
111
|
+
self.indx += 1
|
|
112
|
+
self.size += 1
|
|
113
|
+
|
|
114
|
+
self._wake_waiters()
|
|
115
|
+
|
|
116
|
+
return indx, packitem
|
|
117
|
+
|
|
90
118
|
def first(self):
|
|
91
119
|
|
|
92
120
|
for lkey, lval in self.slab.scanByFull(db=self.db):
|