synapse 2.184.0__py311-none-any.whl → 2.186.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/cortex.py +4 -3
- synapse/datamodel.py +41 -6
- synapse/exc.py +2 -0
- synapse/lib/ast.py +83 -22
- synapse/lib/auth.py +13 -0
- synapse/lib/cell.py +78 -2
- synapse/lib/drive.py +45 -10
- synapse/lib/modules.py +1 -0
- synapse/lib/parser.py +1 -0
- synapse/lib/snap.py +1 -6
- synapse/lib/storm.lark +12 -6
- synapse/lib/storm.py +45 -9
- synapse/lib/storm_format.py +1 -0
- synapse/lib/stormlib/stix.py +14 -5
- synapse/lib/stormtypes.py +64 -36
- synapse/lib/types.py +6 -0
- synapse/lib/version.py +2 -2
- synapse/models/doc.py +93 -0
- synapse/models/infotech.py +2 -1
- synapse/models/media.py +0 -1
- synapse/models/orgs.py +26 -3
- synapse/models/proj.py +56 -36
- synapse/models/risk.py +3 -0
- synapse/models/syn.py +64 -6
- synapse/tests/test_cortex.py +49 -6
- synapse/tests/test_lib_base.py +2 -2
- synapse/tests/test_lib_cell.py +59 -5
- synapse/tests/test_lib_grammar.py +2 -0
- synapse/tests/test_lib_storm.py +54 -1
- synapse/tests/test_lib_stormlib_stix.py +3 -2
- synapse/tests/test_model_doc.py +51 -0
- synapse/tests/test_model_orgs.py +41 -0
- synapse/tests/test_model_risk.py +2 -0
- synapse/tests/test_model_syn.py +43 -0
- synapse/tests/test_tools_promote.py +67 -0
- synapse/tests/test_tools_snapshot.py +47 -0
- synapse/tools/aha/clone.py +3 -1
- synapse/tools/aha/easycert.py +1 -1
- synapse/tools/aha/enroll.py +3 -1
- synapse/tools/aha/provision/service.py +3 -1
- synapse/tools/aha/provision/user.py +3 -1
- synapse/tools/livebackup.py +3 -1
- synapse/tools/promote.py +23 -4
- synapse/tools/snapshot.py +69 -0
- {synapse-2.184.0.dist-info → synapse-2.186.0.dist-info}/METADATA +5 -10
- {synapse-2.184.0.dist-info → synapse-2.186.0.dist-info}/RECORD +49 -44
- {synapse-2.184.0.dist-info → synapse-2.186.0.dist-info}/WHEEL +1 -1
- {synapse-2.184.0.dist-info → synapse-2.186.0.dist-info}/LICENSE +0 -0
- {synapse-2.184.0.dist-info → synapse-2.186.0.dist-info}/top_level.txt +0 -0
synapse/cortex.py
CHANGED
|
@@ -946,7 +946,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
946
946
|
self._exthttpapicache = s_cache.FixedCache(self._getHttpExtApiByPath, size=1000)
|
|
947
947
|
self._initCortexExtHttpApi()
|
|
948
948
|
|
|
949
|
-
self.model = s_datamodel.Model()
|
|
949
|
+
self.model = s_datamodel.Model(core=self)
|
|
950
950
|
|
|
951
951
|
await self._bumpCellVers('cortex:extmodel', (
|
|
952
952
|
(1, self._migrateTaxonomyIface),
|
|
@@ -2056,9 +2056,10 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2056
2056
|
continue
|
|
2057
2057
|
|
|
2058
2058
|
if not regex.fullmatch(regx[i], parts[i]):
|
|
2059
|
-
|
|
2059
|
+
mesg = f'Tag part ({parts[i]}) of tag ({tagname}) does not match the tag model regex: [{regx[i]}]'
|
|
2060
|
+
return (False, mesg)
|
|
2060
2061
|
|
|
2061
|
-
return True
|
|
2062
|
+
return (True, None)
|
|
2062
2063
|
|
|
2063
2064
|
async def getTagPrune(self, tagname):
|
|
2064
2065
|
return self.tagprune.get(tagname)
|
synapse/datamodel.py
CHANGED
|
@@ -482,8 +482,9 @@ class Model:
|
|
|
482
482
|
'''
|
|
483
483
|
The data model used by a Cortex hypergraph.
|
|
484
484
|
'''
|
|
485
|
-
def __init__(self):
|
|
485
|
+
def __init__(self, core=None):
|
|
486
486
|
|
|
487
|
+
self.core = core
|
|
487
488
|
self.types = {} # name: Type()
|
|
488
489
|
self.forms = {} # name: Form()
|
|
489
490
|
self.props = {} # (form,name): Prop() and full: Prop()
|
|
@@ -653,13 +654,16 @@ class Model:
|
|
|
653
654
|
self.formprefixcache[prefix] = forms
|
|
654
655
|
return forms
|
|
655
656
|
|
|
656
|
-
def reqProp(self, name):
|
|
657
|
+
def reqProp(self, name, extra=None):
|
|
657
658
|
prop = self.prop(name)
|
|
658
659
|
if prop is not None:
|
|
659
660
|
return prop
|
|
660
661
|
|
|
661
|
-
|
|
662
|
-
|
|
662
|
+
exc = s_exc.NoSuchProp.init(name)
|
|
663
|
+
if extra is not None:
|
|
664
|
+
exc = extra(exc)
|
|
665
|
+
|
|
666
|
+
raise exc
|
|
663
667
|
|
|
664
668
|
def reqUniv(self, name):
|
|
665
669
|
prop = self.univ(name)
|
|
@@ -1082,6 +1086,30 @@ class Model:
|
|
|
1082
1086
|
self.props[prop.full] = prop
|
|
1083
1087
|
return prop
|
|
1084
1088
|
|
|
1089
|
+
def _prepFormIface(self, form, iface):
|
|
1090
|
+
|
|
1091
|
+
template = iface.get('template', {})
|
|
1092
|
+
template.update(form.type.info.get('template', {}))
|
|
1093
|
+
|
|
1094
|
+
def convert(item):
|
|
1095
|
+
|
|
1096
|
+
if isinstance(item, str):
|
|
1097
|
+
|
|
1098
|
+
if item == '$self':
|
|
1099
|
+
return form.name
|
|
1100
|
+
|
|
1101
|
+
return item.format(**template)
|
|
1102
|
+
|
|
1103
|
+
if isinstance(item, dict):
|
|
1104
|
+
return {convert(k): convert(v) for (k, v) in item.items()}
|
|
1105
|
+
|
|
1106
|
+
if isinstance(item, (list, tuple)):
|
|
1107
|
+
return tuple([convert(v) for v in item])
|
|
1108
|
+
|
|
1109
|
+
return item
|
|
1110
|
+
|
|
1111
|
+
return convert(iface)
|
|
1112
|
+
|
|
1085
1113
|
def _addFormIface(self, form, name, subifaces=None):
|
|
1086
1114
|
|
|
1087
1115
|
iface = self.ifaces.get(name)
|
|
@@ -1094,9 +1122,14 @@ class Model:
|
|
|
1094
1122
|
mesg = f'Form {form.name} depends on deprecated interface {name} which will be removed in 3.0.0'
|
|
1095
1123
|
logger.warning(mesg)
|
|
1096
1124
|
|
|
1125
|
+
iface = self._prepFormIface(form, iface)
|
|
1126
|
+
|
|
1097
1127
|
for propname, typedef, propinfo in iface.get('props', ()):
|
|
1098
|
-
|
|
1099
|
-
|
|
1128
|
+
|
|
1129
|
+
# allow form props to take precedence
|
|
1130
|
+
if form.prop(propname) is not None:
|
|
1131
|
+
continue
|
|
1132
|
+
|
|
1100
1133
|
prop = self._addFormProp(form, propname, typedef, propinfo)
|
|
1101
1134
|
self.ifaceprops[f'{name}:{propname}'].append(prop.full)
|
|
1102
1135
|
|
|
@@ -1123,6 +1156,8 @@ class Model:
|
|
|
1123
1156
|
if (iface := self.ifaces.get(name)) is None:
|
|
1124
1157
|
return
|
|
1125
1158
|
|
|
1159
|
+
iface = self._prepFormIface(form, iface)
|
|
1160
|
+
|
|
1126
1161
|
for propname, typedef, propinfo in iface.get('props', ()):
|
|
1127
1162
|
fullprop = f'{form.name}:{propname}'
|
|
1128
1163
|
self.delFormProp(form.name, propname)
|
synapse/exc.py
CHANGED
synapse/lib/ast.py
CHANGED
|
@@ -1426,6 +1426,32 @@ class LiftOper(Oper):
|
|
|
1426
1426
|
self.astinfo = astinfo
|
|
1427
1427
|
self.reverse = True
|
|
1428
1428
|
|
|
1429
|
+
def getPivNames(self, runt, prop, pivs):
|
|
1430
|
+
pivnames = []
|
|
1431
|
+
typename = prop.type.name
|
|
1432
|
+
for piv in pivs:
|
|
1433
|
+
pivprop = runt.model.reqProp(f'{typename}:{piv}', extra=self.kids[0].addExcInfo)
|
|
1434
|
+
pivnames.append(pivprop.full)
|
|
1435
|
+
typename = pivprop.type.name
|
|
1436
|
+
|
|
1437
|
+
return pivnames
|
|
1438
|
+
|
|
1439
|
+
async def pivlift(self, runt, props, pivnames, genr):
|
|
1440
|
+
|
|
1441
|
+
async def pivvals(prop, pivgenr):
|
|
1442
|
+
async for node in pivgenr:
|
|
1443
|
+
async for pivo in runt.snap.nodesByPropValu(prop, '=', node.ndef[1], reverse=self.reverse):
|
|
1444
|
+
yield pivo
|
|
1445
|
+
|
|
1446
|
+
for pivname in pivnames[-2::-1]:
|
|
1447
|
+
genr = pivvals(pivname, genr)
|
|
1448
|
+
|
|
1449
|
+
async for node in genr:
|
|
1450
|
+
valu = node.ndef[1]
|
|
1451
|
+
for prop in props:
|
|
1452
|
+
async for node in runt.snap.nodesByPropValu(prop.full, '=', valu, reverse=self.reverse):
|
|
1453
|
+
yield node
|
|
1454
|
+
|
|
1429
1455
|
async def run(self, runt, genr):
|
|
1430
1456
|
|
|
1431
1457
|
if self.isRuntSafe(runt):
|
|
@@ -1584,30 +1610,52 @@ class LiftByArray(LiftOper):
|
|
|
1584
1610
|
cmpr = await self.kids[1].compute(runt, path)
|
|
1585
1611
|
valu = await s_stormtypes.tostor(await self.kids[2].compute(runt, path))
|
|
1586
1612
|
|
|
1587
|
-
|
|
1588
|
-
if
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
return
|
|
1613
|
+
pivs = None
|
|
1614
|
+
if name.find('::') != -1:
|
|
1615
|
+
parts = name.split('::')
|
|
1616
|
+
name, pivs = parts[0], parts[1:]
|
|
1592
1617
|
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1618
|
+
if (prop := runt.model.props.get(name)) is not None:
|
|
1619
|
+
props = (prop,)
|
|
1620
|
+
else:
|
|
1621
|
+
proplist = runt.model.ifaceprops.get(name)
|
|
1622
|
+
if proplist is None:
|
|
1623
|
+
raise self.kids[0].addExcInfo(s_exc.NoSuchProp.init(name))
|
|
1596
1624
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1625
|
+
props = []
|
|
1626
|
+
for propname in proplist:
|
|
1627
|
+
props.append(runt.model.props.get(propname))
|
|
1600
1628
|
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1629
|
+
try:
|
|
1630
|
+
if pivs is not None:
|
|
1631
|
+
pivnames = self.getPivNames(runt, props[0], pivs)
|
|
1604
1632
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1633
|
+
genr = runt.snap.nodesByPropArray(pivnames[-1], cmpr, valu, reverse=self.reverse)
|
|
1634
|
+
async for node in self.pivlift(runt, props, pivnames, genr):
|
|
1635
|
+
yield node
|
|
1636
|
+
return
|
|
1608
1637
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1638
|
+
if len(props) == 1:
|
|
1639
|
+
async for node in runt.snap.nodesByPropArray(name, cmpr, valu, reverse=self.reverse):
|
|
1640
|
+
yield node
|
|
1641
|
+
return
|
|
1642
|
+
|
|
1643
|
+
relname = props[0].name
|
|
1644
|
+
def cmprkey(node):
|
|
1645
|
+
return node.props.get(relname)
|
|
1646
|
+
|
|
1647
|
+
genrs = []
|
|
1648
|
+
for prop in props:
|
|
1649
|
+
genrs.append(runt.snap.nodesByPropArray(prop.full, cmpr, valu, reverse=self.reverse))
|
|
1650
|
+
|
|
1651
|
+
async for node in s_common.merggenr2(genrs, cmprkey, reverse=self.reverse):
|
|
1652
|
+
yield node
|
|
1653
|
+
|
|
1654
|
+
except s_exc.BadTypeValu as e:
|
|
1655
|
+
raise self.kids[2].addExcInfo(e)
|
|
1656
|
+
|
|
1657
|
+
except s_exc.SynErr as e:
|
|
1658
|
+
raise self.addExcInfo(e)
|
|
1611
1659
|
|
|
1612
1660
|
class LiftTagProp(LiftOper):
|
|
1613
1661
|
'''
|
|
@@ -1839,6 +1887,11 @@ class LiftPropBy(LiftOper):
|
|
|
1839
1887
|
if not isinstance(valu, s_node.Node):
|
|
1840
1888
|
valu = await s_stormtypes.tostor(valu)
|
|
1841
1889
|
|
|
1890
|
+
pivs = None
|
|
1891
|
+
if name.find('::') != -1:
|
|
1892
|
+
parts = name.split('::')
|
|
1893
|
+
name, pivs = parts[0], parts[1:]
|
|
1894
|
+
|
|
1842
1895
|
prop = runt.model.props.get(name)
|
|
1843
1896
|
if prop is not None:
|
|
1844
1897
|
props = (prop,)
|
|
@@ -1852,6 +1905,14 @@ class LiftPropBy(LiftOper):
|
|
|
1852
1905
|
props.append(runt.model.props.get(propname))
|
|
1853
1906
|
|
|
1854
1907
|
try:
|
|
1908
|
+
if pivs is not None:
|
|
1909
|
+
pivnames = self.getPivNames(runt, props[0], pivs)
|
|
1910
|
+
|
|
1911
|
+
genr = runt.snap.nodesByPropValu(pivnames[-1], cmpr, valu, reverse=self.reverse)
|
|
1912
|
+
async for node in self.pivlift(runt, props, pivnames, genr):
|
|
1913
|
+
yield node
|
|
1914
|
+
return
|
|
1915
|
+
|
|
1855
1916
|
if len(props) == 1:
|
|
1856
1917
|
prop = props[0]
|
|
1857
1918
|
async for node in runt.snap.nodesByPropValu(prop.full, cmpr, valu, reverse=self.reverse):
|
|
@@ -3794,7 +3855,7 @@ class ExprDict(Value):
|
|
|
3794
3855
|
|
|
3795
3856
|
def prepare(self):
|
|
3796
3857
|
self.const = None
|
|
3797
|
-
if all(isinstance(k, Const) for k in self.kids):
|
|
3858
|
+
if all(isinstance(k, Const) and not isinstance(k, EmbedQuery) for k in self.kids):
|
|
3798
3859
|
valu = {}
|
|
3799
3860
|
for i in range(0, len(self.kids), 2):
|
|
3800
3861
|
valu[self.kids[i].value()] = self.kids[i + 1].value()
|
|
@@ -3824,7 +3885,7 @@ class ExprList(Value):
|
|
|
3824
3885
|
|
|
3825
3886
|
def prepare(self):
|
|
3826
3887
|
self.const = None
|
|
3827
|
-
if all(isinstance(k, Const) for k in self.kids):
|
|
3888
|
+
if all(isinstance(k, Const) and not isinstance(k, EmbedQuery) for k in self.kids):
|
|
3828
3889
|
self.const = s_msgpack.en([k.value() for k in self.kids])
|
|
3829
3890
|
|
|
3830
3891
|
async def compute(self, runt, path):
|
|
@@ -4518,7 +4579,7 @@ class EditTagAdd(Edit):
|
|
|
4518
4579
|
else:
|
|
4519
4580
|
oper_offset = 0
|
|
4520
4581
|
|
|
4521
|
-
excignore = (s_exc.BadTypeValu,
|
|
4582
|
+
excignore = (s_exc.BadTypeValu,) if oper_offset == 1 else ()
|
|
4522
4583
|
|
|
4523
4584
|
hasval = len(self.kids) > 2 + oper_offset
|
|
4524
4585
|
|
synapse/lib/auth.py
CHANGED
|
@@ -264,6 +264,19 @@ class Auth(s_nexus.Pusher):
|
|
|
264
264
|
def _getRoleIden(self, name):
|
|
265
265
|
return self.roleidenbyname.get(name)
|
|
266
266
|
|
|
267
|
+
# TODO convert getUserByName() and getRoleByName()
|
|
268
|
+
# back from async? These were plumbed to avoid infecting
|
|
269
|
+
# type norm/repr functions with async...
|
|
270
|
+
def _getRoleByName(self, name):
|
|
271
|
+
roleiden = self.roleidenbynamecache.get(name)
|
|
272
|
+
if roleiden is not None:
|
|
273
|
+
return self.role(roleiden)
|
|
274
|
+
|
|
275
|
+
def _getUserByName(self, name):
|
|
276
|
+
useriden = self.useridenbynamecache.get(name)
|
|
277
|
+
if useriden is not None:
|
|
278
|
+
return self.user(useriden)
|
|
279
|
+
|
|
267
280
|
@s_nexus.Pusher.onPushAuto('user:profile:set')
|
|
268
281
|
async def setUserProfileValu(self, iden, name, valu):
|
|
269
282
|
user = await self.reqUser(iden)
|
synapse/lib/cell.py
CHANGED
|
@@ -35,6 +35,7 @@ import synapse.lib.boss as s_boss
|
|
|
35
35
|
import synapse.lib.coro as s_coro
|
|
36
36
|
import synapse.lib.hive as s_hive
|
|
37
37
|
import synapse.lib.link as s_link
|
|
38
|
+
import synapse.lib.task as s_task
|
|
38
39
|
import synapse.lib.cache as s_cache
|
|
39
40
|
import synapse.lib.const as s_const
|
|
40
41
|
import synapse.lib.drive as s_drive
|
|
@@ -206,6 +207,14 @@ class CellApi(s_base.Base):
|
|
|
206
207
|
async def initCellApi(self):
|
|
207
208
|
pass
|
|
208
209
|
|
|
210
|
+
@adminapi(log=True)
|
|
211
|
+
async def freeze(self, timeout=30):
|
|
212
|
+
return await self.cell.freeze(timeout=timeout)
|
|
213
|
+
|
|
214
|
+
@adminapi(log=True)
|
|
215
|
+
async def resume(self):
|
|
216
|
+
return await self.cell.resume()
|
|
217
|
+
|
|
209
218
|
async def allowed(self, perm, default=None):
|
|
210
219
|
'''
|
|
211
220
|
Check if the user has the requested permission.
|
|
@@ -1102,6 +1111,7 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
1102
1111
|
self.auth = None
|
|
1103
1112
|
self.cellparent = parent
|
|
1104
1113
|
self.sessions = {}
|
|
1114
|
+
self.paused = False
|
|
1105
1115
|
self.isactive = False
|
|
1106
1116
|
self.activebase = None
|
|
1107
1117
|
self.inaugural = False
|
|
@@ -1767,8 +1777,11 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
1767
1777
|
|
|
1768
1778
|
return await self.drive.addItemInfo(info, path=path, reldir=reldir)
|
|
1769
1779
|
|
|
1770
|
-
async def getDriveInfo(self, iden):
|
|
1771
|
-
return self.drive.getItemInfo(iden)
|
|
1780
|
+
async def getDriveInfo(self, iden, typename=None):
|
|
1781
|
+
return self.drive.getItemInfo(iden, typename=typename)
|
|
1782
|
+
|
|
1783
|
+
def reqDriveInfo(self, iden, typename=None):
|
|
1784
|
+
return self.drive.reqItemInfo(iden, typename=typename)
|
|
1772
1785
|
|
|
1773
1786
|
async def getDrivePath(self, path, reldir=s_drive.rootdir):
|
|
1774
1787
|
'''
|
|
@@ -2118,6 +2131,13 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
2118
2131
|
Hand off leadership to a mirror in a transactional fashion.
|
|
2119
2132
|
'''
|
|
2120
2133
|
_dispname = f' ahaname={self.conf.get("aha:name")}' if self.conf.get('aha:name') else ''
|
|
2134
|
+
|
|
2135
|
+
if not self.isactive:
|
|
2136
|
+
mesg = f'HANDOFF: {_dispname} is not the current leader and cannot handoff leadership to' \
|
|
2137
|
+
f' {s_urlhelp.sanitizeUrl(turl)}.'
|
|
2138
|
+
logger.error(mesg)
|
|
2139
|
+
raise s_exc.BadState(mesg=mesg, turl=turl, cursvc=_dispname)
|
|
2140
|
+
|
|
2121
2141
|
logger.warning(f'HANDOFF: Performing leadership handoff to {s_urlhelp.sanitizeUrl(turl)}{_dispname}.')
|
|
2122
2142
|
async with await s_telepath.openurl(turl) as cell:
|
|
2123
2143
|
|
|
@@ -4439,6 +4459,11 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4439
4459
|
Returns:
|
|
4440
4460
|
Dict: A Dictionary of metadata.
|
|
4441
4461
|
'''
|
|
4462
|
+
|
|
4463
|
+
mirror = self.conf.get('mirror')
|
|
4464
|
+
if mirror is not None:
|
|
4465
|
+
mirror = s_urlhelp.sanitizeUrl(mirror)
|
|
4466
|
+
|
|
4442
4467
|
ret = {
|
|
4443
4468
|
'synapse': {
|
|
4444
4469
|
'commit': s_version.commit,
|
|
@@ -4449,6 +4474,7 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4449
4474
|
'run': await self.getCellRunId(),
|
|
4450
4475
|
'type': self.getCellType(),
|
|
4451
4476
|
'iden': self.getCellIden(),
|
|
4477
|
+
'paused': self.paused,
|
|
4452
4478
|
'active': self.isactive,
|
|
4453
4479
|
'started': self.startms,
|
|
4454
4480
|
'ready': self.nexsroot.ready.is_set(),
|
|
@@ -4458,6 +4484,7 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4458
4484
|
'cellvers': dict(self.cellvers.items()),
|
|
4459
4485
|
'nexsindx': await self.getNexsIndx(),
|
|
4460
4486
|
'uplink': self.nexsroot.miruplink.is_set(),
|
|
4487
|
+
'mirror': mirror,
|
|
4461
4488
|
'aha': {
|
|
4462
4489
|
'name': self.conf.get('aha:name'),
|
|
4463
4490
|
'leader': self.conf.get('aha:leader'),
|
|
@@ -4919,3 +4946,52 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4919
4946
|
|
|
4920
4947
|
key = tuple(sorted(opts.items()))
|
|
4921
4948
|
return self._sslctx_cache.get(key)
|
|
4949
|
+
|
|
4950
|
+
async def freeze(self, timeout=30):
|
|
4951
|
+
|
|
4952
|
+
if self.paused:
|
|
4953
|
+
mesg = 'The service is already frozen.'
|
|
4954
|
+
raise s_exc.BadState(mesg=mesg)
|
|
4955
|
+
|
|
4956
|
+
logger.warning(f'Freezing service for volume snapshot.')
|
|
4957
|
+
|
|
4958
|
+
logger.warning('...acquiring nexus lock to prevent edits.')
|
|
4959
|
+
|
|
4960
|
+
try:
|
|
4961
|
+
await asyncio.wait_for(self.nexslock.acquire(), timeout=timeout)
|
|
4962
|
+
|
|
4963
|
+
except asyncio.TimeoutError:
|
|
4964
|
+
logger.warning('...nexus lock acquire timed out!')
|
|
4965
|
+
logger.warning('Aborting freeze and resuming normal operation.')
|
|
4966
|
+
|
|
4967
|
+
mesg = 'Nexus lock acquire timed out.'
|
|
4968
|
+
raise s_exc.TimeOut(mesg=mesg)
|
|
4969
|
+
|
|
4970
|
+
self.paused = True
|
|
4971
|
+
|
|
4972
|
+
try:
|
|
4973
|
+
|
|
4974
|
+
logger.warning('...committing pending transactions.')
|
|
4975
|
+
await self.slab.syncLoopOnce()
|
|
4976
|
+
|
|
4977
|
+
logger.warning('...flushing dirty buffers to disk.')
|
|
4978
|
+
await s_task.executor(os.sync)
|
|
4979
|
+
|
|
4980
|
+
logger.warning('...done!')
|
|
4981
|
+
|
|
4982
|
+
except Exception:
|
|
4983
|
+
self.paused = False
|
|
4984
|
+
self.nexslock.release()
|
|
4985
|
+
logger.exception('Failed to freeze. Resuming normal operation.')
|
|
4986
|
+
raise
|
|
4987
|
+
|
|
4988
|
+
async def resume(self):
|
|
4989
|
+
|
|
4990
|
+
if not self.paused:
|
|
4991
|
+
mesg = 'The service is not frozen.'
|
|
4992
|
+
raise s_exc.BadState(mesg=mesg)
|
|
4993
|
+
|
|
4994
|
+
logger.warning('Resuming normal operations from a freeze.')
|
|
4995
|
+
|
|
4996
|
+
self.paused = False
|
|
4997
|
+
self.nexslock.release()
|
synapse/lib/drive.py
CHANGED
|
@@ -22,6 +22,7 @@ LKEY_INFO = b'\x02' # <bidn> = <info>
|
|
|
22
22
|
LKEY_DATA = b'\x03' # <bidn> <vers> = <data>
|
|
23
23
|
LKEY_VERS = b'\x04' # <bidn> <vers> = <versinfo>
|
|
24
24
|
LKEY_INFO_BYTYPE = b'\x05' # <type> 00 <bidn> = 01
|
|
25
|
+
LKEY_TYPE_VERS = b'\x06' # <type> = <uint64>
|
|
25
26
|
|
|
26
27
|
rootdir = '00000000000000000000000000000000'
|
|
27
28
|
|
|
@@ -60,24 +61,36 @@ class Drive(s_base.Base):
|
|
|
60
61
|
|
|
61
62
|
return [reqValidName(p.strip().lower()) for p in path]
|
|
62
63
|
|
|
63
|
-
def
|
|
64
|
-
|
|
64
|
+
def _reqInfoType(self, info, typename):
|
|
65
|
+
infotype = info.get('type')
|
|
66
|
+
if infotype != typename:
|
|
67
|
+
mesg = f'Drive item has the wrong type. Expected: {typename} got {infotype}.'
|
|
68
|
+
raise s_exc.TypeMismatch(mesg=mesg, expected=typename, got=infotype)
|
|
69
|
+
|
|
70
|
+
def getItemInfo(self, iden, typename=None):
|
|
71
|
+
info = self._getItemInfo(s_common.uhex(iden))
|
|
72
|
+
if typename is not None:
|
|
73
|
+
self._reqInfoType(info, typename)
|
|
74
|
+
return info
|
|
65
75
|
|
|
66
76
|
def _getItemInfo(self, bidn):
|
|
67
77
|
byts = self.slab.get(LKEY_INFO + bidn, db=self.dbname)
|
|
68
78
|
if byts is not None:
|
|
69
79
|
return s_msgpack.un(byts)
|
|
70
80
|
|
|
71
|
-
def reqItemInfo(self, iden):
|
|
72
|
-
return self._reqItemInfo(s_common.uhex(iden))
|
|
81
|
+
def reqItemInfo(self, iden, typename=None):
|
|
82
|
+
return self._reqItemInfo(s_common.uhex(iden), typename=typename)
|
|
73
83
|
|
|
74
|
-
def _reqItemInfo(self, bidn):
|
|
84
|
+
def _reqItemInfo(self, bidn, typename=None):
|
|
75
85
|
info = self._getItemInfo(bidn)
|
|
76
|
-
if info is
|
|
77
|
-
|
|
86
|
+
if info is None:
|
|
87
|
+
mesg = f'No drive item with ID {s_common.ehex(bidn)}.'
|
|
88
|
+
raise s_exc.NoSuchIden(mesg=mesg)
|
|
78
89
|
|
|
79
|
-
|
|
80
|
-
|
|
90
|
+
if typename is not None:
|
|
91
|
+
self._reqInfoType(info, typename)
|
|
92
|
+
|
|
93
|
+
return info
|
|
81
94
|
|
|
82
95
|
async def setItemPath(self, iden, path):
|
|
83
96
|
'''
|
|
@@ -494,10 +507,27 @@ class Drive(s_base.Base):
|
|
|
494
507
|
if byts is not None:
|
|
495
508
|
return s_msgpack.un(byts)
|
|
496
509
|
|
|
497
|
-
|
|
510
|
+
def getTypeSchemaVersion(self, typename):
|
|
511
|
+
verskey = LKEY_TYPE_VERS + typename.encode()
|
|
512
|
+
byts = self.slab.get(verskey, db=self.dbname)
|
|
513
|
+
if byts is not None:
|
|
514
|
+
return s_msgpack.un(byts)
|
|
515
|
+
|
|
516
|
+
async def setTypeSchema(self, typename, schema, callback=None, vers=None):
|
|
498
517
|
|
|
499
518
|
reqValidName(typename)
|
|
500
519
|
|
|
520
|
+
if vers is not None:
|
|
521
|
+
vers = int(vers)
|
|
522
|
+
curv = self.getTypeSchemaVersion(typename)
|
|
523
|
+
if curv is not None:
|
|
524
|
+
if vers == curv:
|
|
525
|
+
return False
|
|
526
|
+
|
|
527
|
+
if vers < curv:
|
|
528
|
+
mesg = f'Cannot downgrade drive schema version for type {typename}.'
|
|
529
|
+
raise s_exc.BadVersion(mesg=mesg)
|
|
530
|
+
|
|
501
531
|
vtor = s_config.getJsValidator(schema)
|
|
502
532
|
|
|
503
533
|
self.validators[typename] = vtor
|
|
@@ -506,6 +536,10 @@ class Drive(s_base.Base):
|
|
|
506
536
|
|
|
507
537
|
self.slab.put(lkey, s_msgpack.en(schema), db=self.dbname)
|
|
508
538
|
|
|
539
|
+
if vers is not None:
|
|
540
|
+
verskey = LKEY_TYPE_VERS + typename.encode()
|
|
541
|
+
self.slab.put(verskey, s_msgpack.en(vers), db=self.dbname)
|
|
542
|
+
|
|
509
543
|
if callback is not None:
|
|
510
544
|
async for info in self.getItemsByType(typename):
|
|
511
545
|
bidn = s_common.uhex(info.get('iden'))
|
|
@@ -516,6 +550,7 @@ class Drive(s_base.Base):
|
|
|
516
550
|
vtor(data)
|
|
517
551
|
self.slab.put(LKEY_DATA + bidn + versindx, s_msgpack.en(data), db=self.dbname)
|
|
518
552
|
await asyncio.sleep(0)
|
|
553
|
+
return True
|
|
519
554
|
|
|
520
555
|
async def getItemsByType(self, typename):
|
|
521
556
|
tkey = typename.encode() + b'\x00'
|
synapse/lib/modules.py
CHANGED
synapse/lib/parser.py
CHANGED
synapse/lib/snap.py
CHANGED
|
@@ -1559,12 +1559,6 @@ class Snap(s_base.Base):
|
|
|
1559
1559
|
return await self.tagnorms.aget(tagname)
|
|
1560
1560
|
|
|
1561
1561
|
async def _getTagNorm(self, tagname):
|
|
1562
|
-
|
|
1563
|
-
if not self.core.isTagValid(tagname):
|
|
1564
|
-
mesg = f'The tag ({tagname}) does not meet the regex for the tree.'
|
|
1565
|
-
await self._raiseOnStrict(s_exc.BadTag, mesg)
|
|
1566
|
-
return None
|
|
1567
|
-
|
|
1568
1562
|
try:
|
|
1569
1563
|
return self.core.model.type('syn:tag').norm(tagname)
|
|
1570
1564
|
except s_exc.BadTypeValu as e:
|
|
@@ -1692,6 +1686,7 @@ class Snap(s_base.Base):
|
|
|
1692
1686
|
|
|
1693
1687
|
todo = s_common.todo('runRuntLift', full, valu, cmpr, self.view.iden)
|
|
1694
1688
|
async for sode in self.core.dyniter('cortex', todo):
|
|
1689
|
+
await asyncio.sleep(0)
|
|
1695
1690
|
|
|
1696
1691
|
node = s_node.Node(self, sode)
|
|
1697
1692
|
node.isrunt = True
|
synapse/lib/storm.lark
CHANGED
|
@@ -222,9 +222,9 @@ liftreverse: _REVERSE "(" (liftformtag | liftpropby | liftprop | liftbyarray | l
|
|
|
222
222
|
_DEREF.3: /\*(?=\$)/
|
|
223
223
|
|
|
224
224
|
liftformtag: ((PROPS | UNIVNAME | WILDPROPS) | _DEREF _varvalu) tagname [_cmpr _valu]
|
|
225
|
-
liftpropby: ((PROPS | UNIVNAME) | _DEREF _varvalu) _cmpr _valu
|
|
225
|
+
liftpropby: ((PROPS | EMBEDPROPS | UNIVNAME) | _DEREF _varvalu) _cmpr _valu
|
|
226
226
|
liftprop: ((PROPS | UNIVNAME | WILDPROPS) | _DEREF _varvalu)
|
|
227
|
-
liftbyarray: ((PROPS | UNIVNAME) | _DEREF _varvalu) "*[" _safe_cmpr _valu "]"
|
|
227
|
+
liftbyarray: ((PROPS | EMBEDPROPS | UNIVNAME) | _DEREF _varvalu) "*[" _safe_cmpr _valu "]"
|
|
228
228
|
lifttagtag: (_HASH | _HASHSPACE) tagname [_cmpr _valu]
|
|
229
229
|
liftbytag: (tagname | tagnamewithspace) [_cmpr _valu]
|
|
230
230
|
liftbytagprop: (tagprop | tagpropwithspace) [_cmpr _valu]
|
|
@@ -321,10 +321,10 @@ _valu: _basevalu | NONQUOTEWORD
|
|
|
321
321
|
evalvalu: _valu
|
|
322
322
|
exprdict: "{" ((_exprvalu | VARTOKN) (":" | _EXPRCOLONNOSPACE) (_exprvalu | VARTOKN) ("," (_exprvalu | VARTOKN) (":" | _EXPRCOLONNOSPACE) (_exprvalu | VARTOKN))* ","? )? "}"
|
|
323
323
|
exprlist: "[" ((_exprvalu | VARTOKN) ("," (_exprvalu | VARTOKN))* ","? )? "]"
|
|
324
|
-
// Just like _valu, but doesn't allow valu lists or unquoted strings
|
|
324
|
+
// Just like _valu, but doesn't allow valu lists or unquoted strings
|
|
325
325
|
_exprvalu: NUMBER | HEXNUMBER | OCTNUMBER | BOOL | NULL | exprlist | exprdict | _exprvarvalu | exprrelpropvalu
|
|
326
326
|
| exprunivpropvalu | exprtagvalu | exprtagpropvalu | TRIPLEQUOTEDSTRING | DOUBLEQUOTEDSTRING
|
|
327
|
-
| SINGLEQUOTEDSTRING | formatstring | _innerdollarexprs
|
|
327
|
+
| SINGLEQUOTEDSTRING | formatstring | _innerdollarexprs | embedquery
|
|
328
328
|
|
|
329
329
|
// Expr versions of rules to avoid invalid state merges
|
|
330
330
|
_innerdollarexprs: "$"? innerdollaroper
|
|
@@ -454,8 +454,14 @@ formatstring: "`" (_formatexpr | FORMATTEXT)* "`"
|
|
|
454
454
|
|
|
455
455
|
// Must be kept consistent with same regexes in synapse/lib/grammar.py
|
|
456
456
|
// A full property. Must contain at least 1 colon
|
|
457
|
-
PROPS.
|
|
458
|
-
|
|
457
|
+
PROPS.3: /[a-z_][a-z0-9_]*(:[a-z0-9_]+)+([:.][a-z0-9_]+)*(?![:.a-z0-9_\-])/
|
|
458
|
+
|
|
459
|
+
// A full property containing a wildcard
|
|
460
|
+
WILDPROPS.3: /[a-z_][a-z0-9_]*(:\*|(:[a-z0-9_]+)+([:.][a-z0-9_]+)*:?\*)(?![:.a-z0-9_\-\[])/
|
|
461
|
+
|
|
462
|
+
// A full property with embed properties
|
|
463
|
+
EMBEDPROPS.2: /[a-z_][a-z0-9_]*(:[a-z0-9_]+)+((\:\:|\:|\.)[a-z0-9_]+)*(?![:.a-z0-9_\-])/
|
|
464
|
+
|
|
459
465
|
// A universal property
|
|
460
466
|
UNIVNAME.2: /(?<=^|[\s\|\{\(\[+=-])\.[a-z_][a-z0-9_]*([:.][a-z0-9_]+)*/
|
|
461
467
|
univprop: UNIVNAME | "." _varvalu
|