synapse 2.185.0__py311-none-any.whl → 2.187.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.

Files changed (43) hide show
  1. synapse/cortex.py +5 -4
  2. synapse/exc.py +2 -0
  3. synapse/lib/ast.py +1 -1
  4. synapse/lib/cell.py +65 -2
  5. synapse/lib/drive.py +45 -10
  6. synapse/lib/hive.py +1 -1
  7. synapse/lib/modelrev.py +771 -11
  8. synapse/lib/snap.py +0 -6
  9. synapse/lib/spooled.py +26 -3
  10. synapse/lib/storm.py +7 -0
  11. synapse/lib/stormlib/model.py +320 -250
  12. synapse/lib/stormtypes.py +36 -10
  13. synapse/lib/types.py +6 -0
  14. synapse/lib/version.py +2 -2
  15. synapse/models/infotech.py +49 -22
  16. synapse/models/risk.py +3 -0
  17. synapse/tests/test_cortex.py +10 -5
  18. synapse/tests/test_lib_base.py +2 -2
  19. synapse/tests/test_lib_cell.py +16 -4
  20. synapse/tests/test_lib_modelrev.py +918 -379
  21. synapse/tests/test_lib_spooled.py +34 -0
  22. synapse/tests/test_lib_stormlib_model.py +0 -270
  23. synapse/tests/test_lib_stormtypes.py +11 -0
  24. synapse/tests/test_model_infotech.py +14 -11
  25. synapse/tests/test_model_risk.py +2 -0
  26. synapse/tests/test_tools_snapshot.py +47 -0
  27. synapse/tools/aha/clone.py +3 -1
  28. synapse/tools/aha/easycert.py +1 -1
  29. synapse/tools/aha/enroll.py +3 -1
  30. synapse/tools/aha/provision/service.py +3 -1
  31. synapse/tools/aha/provision/user.py +3 -1
  32. synapse/tools/changelog.py +11 -3
  33. synapse/tools/livebackup.py +3 -1
  34. synapse/tools/promote.py +9 -3
  35. synapse/tools/snapshot.py +69 -0
  36. {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/METADATA +1 -1
  37. {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/RECORD +40 -41
  38. {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/WHEEL +1 -1
  39. synapse/assets/__init__.py +0 -35
  40. synapse/assets/storm/migrations/model-0.2.28.storm +0 -355
  41. synapse/tests/test_assets.py +0 -25
  42. {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/LICENSE +0 -0
  43. {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/top_level.txt +0 -0
synapse/cortex.py CHANGED
@@ -1938,12 +1938,12 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1938
1938
  return
1939
1939
 
1940
1940
  async def coreQueuePuts(self, name, items):
1941
- await self._push('queue:puts', name, items)
1941
+ return await self._push('queue:puts', name, items)
1942
1942
 
1943
1943
  @s_nexus.Pusher.onPush('queue:puts', passitem=True)
1944
1944
  async def _coreQueuePuts(self, name, items, nexsitem):
1945
1945
  nexsoff, nexsmesg = nexsitem
1946
- await self.multiqueue.puts(name, items, reqid=nexsoff)
1946
+ return await self.multiqueue.puts(name, items, reqid=nexsoff)
1947
1947
 
1948
1948
  @s_nexus.Pusher.onPushAuto('queue:cull')
1949
1949
  async def coreQueueCull(self, name, offs):
@@ -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
- return False
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/exc.py CHANGED
@@ -141,6 +141,8 @@ class BadTag(SynErr): pass
141
141
  class BadTime(SynErr): pass
142
142
  class BadUrl(SynErr): pass
143
143
 
144
+ class TypeMismatch(SynErr): pass
145
+
144
146
  class CantDelCmd(SynErr): pass
145
147
  class CantDelNode(SynErr): pass
146
148
  class CantDelForm(SynErr): pass
synapse/lib/ast.py CHANGED
@@ -4579,7 +4579,7 @@ class EditTagAdd(Edit):
4579
4579
  else:
4580
4580
  oper_offset = 0
4581
4581
 
4582
- excignore = (s_exc.BadTypeValu, s_exc.BadTag) if oper_offset == 1 else ()
4582
+ excignore = (s_exc.BadTypeValu,) if oper_offset == 1 else ()
4583
4583
 
4584
4584
  hasval = len(self.kids) > 2 + oper_offset
4585
4585
 
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
  '''
@@ -4461,6 +4474,7 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
4461
4474
  'run': await self.getCellRunId(),
4462
4475
  'type': self.getCellType(),
4463
4476
  'iden': self.getCellIden(),
4477
+ 'paused': self.paused,
4464
4478
  'active': self.isactive,
4465
4479
  'started': self.startms,
4466
4480
  'ready': self.nexsroot.ready.is_set(),
@@ -4932,3 +4946,52 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
4932
4946
 
4933
4947
  key = tuple(sorted(opts.items()))
4934
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 getItemInfo(self, iden):
64
- return self._getItemInfo(s_common.uhex(iden))
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 not None:
77
- return info
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
- mesg = f'No drive item with ID {s_common.ehex(bidn)}.'
80
- raise s_exc.NoSuchIden(mesg=mesg)
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
- async def setTypeSchema(self, typename, schema, callback=None):
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/hive.py CHANGED
@@ -351,7 +351,7 @@ class Hive(s_nexus.Pusher, s_telepath.Aware):
351
351
  await self.cell.auth._hndlsetUserProfileValu(iden, name, valu)
352
352
 
353
353
  elif full[0] == 'cellvers':
354
- self.cell.setCellVers(full[-1], valu, nexs=False)
354
+ await self.cell.setCellVers(full[-1], valu, nexs=False)
355
355
 
356
356
  node = await self._getHiveNode(full)
357
357