synapse 2.195.1__py311-none-any.whl → 2.196.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 +72 -5
- synapse/common.py +23 -0
- synapse/cortex.py +1 -0
- synapse/daemon.py +1 -0
- synapse/lib/aha.py +159 -4
- synapse/lib/cell.py +133 -8
- synapse/lib/jsonstor.py +2 -1
- synapse/lib/modelrev.py +5 -1
- synapse/lib/nexus.py +4 -1
- synapse/lib/reflect.py +4 -5
- synapse/lib/snap.py +14 -7
- synapse/lib/stormlib/aha.py +351 -1
- synapse/lib/stormlib/utils.py +37 -0
- synapse/lib/stormtypes.py +118 -0
- synapse/lib/version.py +2 -2
- synapse/models/base.py +3 -0
- synapse/models/infotech.py +55 -16
- synapse/models/orgs.py +14 -10
- synapse/models/risk.py +23 -10
- synapse/models/transport.py +8 -3
- synapse/telepath.py +12 -0
- synapse/tests/test_axon.py +23 -0
- synapse/tests/test_common.py +28 -0
- synapse/tests/test_datamodel.py +8 -0
- synapse/tests/test_lib_aha.py +241 -0
- synapse/tests/test_lib_cell.py +61 -0
- synapse/tests/test_lib_jsonstor.py +1 -0
- synapse/tests/test_lib_modelrev.py +6 -0
- synapse/tests/test_lib_stormlib_aha.py +188 -0
- synapse/tests/test_lib_stormlib_utils.py +14 -0
- synapse/tests/test_lib_stormtypes.py +90 -3
- synapse/tests/test_model_base.py +2 -0
- synapse/tests/test_model_infotech.py +28 -1
- synapse/tests/test_model_orgs.py +2 -0
- synapse/tests/test_model_risk.py +2 -0
- synapse/tests/test_model_transport.py +1 -0
- synapse/tests/test_telepath.py +26 -0
- synapse/tests/test_tools_aha.py +192 -0
- synapse/tools/aha/mirror.py +193 -0
- synapse/tools/changelog.py +32 -27
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/METADATA +1 -1
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/RECORD +45 -42
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/LICENSE +0 -0
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/WHEEL +0 -0
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/top_level.txt +0 -0
synapse/axon.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import csv
|
|
2
2
|
import json
|
|
3
|
+
import struct
|
|
3
4
|
import asyncio
|
|
4
5
|
import hashlib
|
|
5
6
|
import logging
|
|
@@ -759,6 +760,26 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
|
|
|
759
760
|
async for item in self.cell.jsonlines(sha256, errors=errors):
|
|
760
761
|
yield item
|
|
761
762
|
|
|
763
|
+
async def unpack(self, sha256, fmt, offs=0):
|
|
764
|
+
'''
|
|
765
|
+
Unpack bytes from a file in the Axon using struct.
|
|
766
|
+
|
|
767
|
+
Args:
|
|
768
|
+
sha256 (bytes): The sha256 hash of the file in bytes.
|
|
769
|
+
fmt (str): The struct format string.
|
|
770
|
+
offs (int): The offset to start reading from.
|
|
771
|
+
|
|
772
|
+
Returns:
|
|
773
|
+
tuple: The unpacked values.
|
|
774
|
+
|
|
775
|
+
Raises:
|
|
776
|
+
synapse.exc.NoSuchFile: If the file does not exist.
|
|
777
|
+
synapse.exc.BadArg: If the struct format is invalid or reads too much data.
|
|
778
|
+
synapse.exc.BadDataValu: If the file does not contain the expected number of bytes.
|
|
779
|
+
synapse.exc.FeatureNotSupported: Feature is not supported.
|
|
780
|
+
'''
|
|
781
|
+
await self._reqUserAllowed(('axon', 'get'))
|
|
782
|
+
return await self.cell.unpack(sha256, fmt, offs=offs)
|
|
762
783
|
|
|
763
784
|
class Axon(s_cell.Cell):
|
|
764
785
|
|
|
@@ -816,6 +837,15 @@ class Axon(s_cell.Cell):
|
|
|
816
837
|
# modularize blob storage
|
|
817
838
|
await self._initBlobStor()
|
|
818
839
|
|
|
840
|
+
# Set the byterange flag as an integer AFTER we've called
|
|
841
|
+
# _initBlobStor which may set it to true. That will allow
|
|
842
|
+
# downstream implementations to continue working as expected
|
|
843
|
+
# out of the gate.
|
|
844
|
+
self.features.update({
|
|
845
|
+
'byterange': int(self.byterange),
|
|
846
|
+
'unpack': 1,
|
|
847
|
+
})
|
|
848
|
+
|
|
819
849
|
async def initServiceRuntime(self):
|
|
820
850
|
|
|
821
851
|
# share ourself via the cell dmon as "axon"
|
|
@@ -825,11 +855,6 @@ class Axon(s_cell.Cell):
|
|
|
825
855
|
self._initAxonHttpApi()
|
|
826
856
|
self.addHealthFunc(self._axonHealth)
|
|
827
857
|
|
|
828
|
-
async def getCellInfo(self):
|
|
829
|
-
info = await s_cell.Cell.getCellInfo(self)
|
|
830
|
-
info['features']['byterange'] = self.byterange
|
|
831
|
-
return info
|
|
832
|
-
|
|
833
858
|
@contextlib.asynccontextmanager
|
|
834
859
|
async def holdHashLock(self, hashbyts):
|
|
835
860
|
'''
|
|
@@ -1487,6 +1512,48 @@ class Axon(s_cell.Cell):
|
|
|
1487
1512
|
raise s_exc.BadJsonText(mesg=f'Bad json line encountered while processing {sha256}, ({e})',
|
|
1488
1513
|
sha256=sha256) from None
|
|
1489
1514
|
|
|
1515
|
+
async def unpack(self, sha256, fmt, offs=0):
|
|
1516
|
+
'''
|
|
1517
|
+
Unpack bytes from a file in the Axon using struct.
|
|
1518
|
+
|
|
1519
|
+
Args:
|
|
1520
|
+
sha256 (bytes): The sha256 hash of the file in bytes.
|
|
1521
|
+
fmt (str): The struct format string.
|
|
1522
|
+
offs (int): The offset to start reading from.
|
|
1523
|
+
|
|
1524
|
+
Returns:
|
|
1525
|
+
tuple: The unpacked values.
|
|
1526
|
+
|
|
1527
|
+
Raises:
|
|
1528
|
+
synapse.exc.NoSuchFile: If the file does not exist.
|
|
1529
|
+
synapse.exc.BadArg: If the struct format is invalid.
|
|
1530
|
+
synapse.exc.BadDataValu: If the expected number of bytes is not received.
|
|
1531
|
+
synapse.exc.FeatureNotSupported: Feature is not supported.
|
|
1532
|
+
'''
|
|
1533
|
+
|
|
1534
|
+
if not isinstance(fmt, str):
|
|
1535
|
+
raise s_exc.BadArg(mesg='Format string must be a string', fmt=fmt)
|
|
1536
|
+
|
|
1537
|
+
try:
|
|
1538
|
+
size = struct.calcsize(fmt)
|
|
1539
|
+
|
|
1540
|
+
if size > s_const.mebibyte:
|
|
1541
|
+
raise s_exc.BadArg(mesg=f'Struct format would read too much data: {size} bytes', size=size)
|
|
1542
|
+
|
|
1543
|
+
byts = b''
|
|
1544
|
+
async for chunk in self.get(sha256, offs=offs, size=size):
|
|
1545
|
+
byts += chunk
|
|
1546
|
+
|
|
1547
|
+
if len(byts) != size:
|
|
1548
|
+
mesg = f'Expected {size} bytes but got {len(byts)} bytes'
|
|
1549
|
+
raise s_exc.BadDataValu(mesg=mesg, expected=size, received=len(byts))
|
|
1550
|
+
|
|
1551
|
+
return struct.unpack(fmt, byts)
|
|
1552
|
+
|
|
1553
|
+
except struct.error as e:
|
|
1554
|
+
mesg = f'Failed to unpack bytes with format {fmt}: {str(e)}'
|
|
1555
|
+
raise s_exc.BadArg(mesg=mesg) from None
|
|
1556
|
+
|
|
1490
1557
|
async def postfiles(self, fields, url, params=None, headers=None, method='POST',
|
|
1491
1558
|
ssl=True, timeout=None, proxy=True, ssl_opts=None):
|
|
1492
1559
|
'''
|
synapse/common.py
CHANGED
|
@@ -1383,6 +1383,29 @@ def _timeout(delay):
|
|
|
1383
1383
|
"""
|
|
1384
1384
|
loop = asyncio.get_running_loop()
|
|
1385
1385
|
return _Timeout(loop.time() + delay if delay is not None else None)
|
|
1386
|
+
# End - Vendored Code from Python 3.12+
|
|
1387
|
+
|
|
1388
|
+
async def waitretn(futu, timeout):
|
|
1389
|
+
try:
|
|
1390
|
+
valu = await wait_for(futu, timeout)
|
|
1391
|
+
return (True, valu)
|
|
1392
|
+
except Exception as e:
|
|
1393
|
+
return (False, excinfo(e))
|
|
1394
|
+
|
|
1395
|
+
async def waitgenr(genr, timeout):
|
|
1396
|
+
|
|
1397
|
+
async with contextlib.aclosing(genr.__aiter__()) as genr:
|
|
1398
|
+
|
|
1399
|
+
while True:
|
|
1400
|
+
retn = await waitretn(genr.__anext__(), timeout)
|
|
1401
|
+
|
|
1402
|
+
if not retn[0] and retn[1]['err'] == 'StopAsyncIteration':
|
|
1403
|
+
return
|
|
1404
|
+
|
|
1405
|
+
yield retn
|
|
1406
|
+
|
|
1407
|
+
if not retn[0]:
|
|
1408
|
+
return
|
|
1386
1409
|
|
|
1387
1410
|
def format(text, **kwargs):
|
|
1388
1411
|
'''
|
synapse/cortex.py
CHANGED
|
@@ -83,6 +83,7 @@ import synapse.lib.stormlib.model as s_stormlib_model
|
|
|
83
83
|
import synapse.lib.stormlib.oauth as s_stormlib_oauth # NOQA
|
|
84
84
|
import synapse.lib.stormlib.stats as s_stormlib_stats # NOQA
|
|
85
85
|
import synapse.lib.stormlib.storm as s_stormlib_storm # NOQA
|
|
86
|
+
import synapse.lib.stormlib.utils as s_stormlib_utils # NOQA
|
|
86
87
|
import synapse.lib.stormlib.vault as s_stormlib_vault # NOQA
|
|
87
88
|
import synapse.lib.stormlib.backup as s_stormlib_backup # NOQA
|
|
88
89
|
import synapse.lib.stormlib.cortex as s_stormlib_cortex # NOQA
|
synapse/daemon.py
CHANGED
|
@@ -462,6 +462,7 @@ class Daemon(s_base.Base):
|
|
|
462
462
|
link.set('sess', sess)
|
|
463
463
|
|
|
464
464
|
if isinstance(item, s_telepath.Aware):
|
|
465
|
+
reply[1]['features'] = await item.getTeleFeats()
|
|
465
466
|
item = await s_coro.ornot(item.getTeleApi, link, mesg, path)
|
|
466
467
|
if isinstance(item, s_base.Base):
|
|
467
468
|
link.onfini(item)
|
synapse/lib/aha.py
CHANGED
|
@@ -132,10 +132,18 @@ class AhaApi(s_cell.CellApi):
|
|
|
132
132
|
|
|
133
133
|
async def getAhaUrls(self, user='root'):
|
|
134
134
|
ahaurls = await self.cell.getAhaUrls(user=user)
|
|
135
|
-
if ahaurls is None:
|
|
136
|
-
return ()
|
|
137
135
|
return ahaurls
|
|
138
136
|
|
|
137
|
+
@s_cell.adminapi()
|
|
138
|
+
async def callAhaPeerApi(self, iden, todo, timeout=None, skiprun=None):
|
|
139
|
+
async for item in self.cell.callAhaPeerApi(iden, todo, timeout=timeout, skiprun=skiprun):
|
|
140
|
+
yield item
|
|
141
|
+
|
|
142
|
+
@s_cell.adminapi()
|
|
143
|
+
async def callAhaPeerGenr(self, iden, todo, timeout=None, skiprun=None):
|
|
144
|
+
async for item in self.cell.callAhaPeerGenr(iden, todo, timeout=timeout, skiprun=skiprun):
|
|
145
|
+
yield item
|
|
146
|
+
|
|
139
147
|
async def getAhaSvc(self, name, filters=None):
|
|
140
148
|
'''
|
|
141
149
|
Return an AHA service description dictionary for a service name.
|
|
@@ -366,7 +374,6 @@ class AhaApi(s_cell.CellApi):
|
|
|
366
374
|
'''
|
|
367
375
|
return await self.cell.clearAhaClones()
|
|
368
376
|
|
|
369
|
-
|
|
370
377
|
class ProvDmon(s_daemon.Daemon):
|
|
371
378
|
|
|
372
379
|
async def __anit__(self, aha):
|
|
@@ -571,7 +578,8 @@ class AhaCell(s_cell.Cell):
|
|
|
571
578
|
|
|
572
579
|
async def initServiceStorage(self):
|
|
573
580
|
|
|
574
|
-
|
|
581
|
+
self.features['callpeers'] = 1
|
|
582
|
+
|
|
575
583
|
dirn = s_common.gendir(self.dirn, 'slabs', 'jsonstor')
|
|
576
584
|
|
|
577
585
|
slab = await s_lmdbslab.Slab.anit(dirn)
|
|
@@ -682,8 +690,126 @@ class AhaCell(s_cell.Cell):
|
|
|
682
690
|
self.addHttpApi('/api/v1/aha/services', AhaServicesV1, {'cell': self})
|
|
683
691
|
self.addHttpApi('/api/v1/aha/provision/service', AhaProvisionServiceV1, {'cell': self})
|
|
684
692
|
|
|
693
|
+
async def callAhaSvcApi(self, name, todo, timeout=None):
|
|
694
|
+
name = self._getAhaName(name)
|
|
695
|
+
svcdef = await self._getAhaSvc(name)
|
|
696
|
+
return self._callAhaSvcApi(svcdef, todo, timeout=timeout)
|
|
697
|
+
|
|
698
|
+
async def _callAhaSvcApi(self, svcdef, todo, timeout=None):
|
|
699
|
+
try:
|
|
700
|
+
proxy = await self.getAhaSvcProxy(svcdef, timeout=timeout)
|
|
701
|
+
meth = getattr(proxy, todo[0])
|
|
702
|
+
return await s_common.waitretn(meth(*todo[1], **todo[2]), timeout=timeout)
|
|
703
|
+
except Exception as e:
|
|
704
|
+
# in case proxy construction fails
|
|
705
|
+
return (False, s_common.excinfo(e))
|
|
706
|
+
|
|
707
|
+
async def _callAhaSvcGenr(self, svcdef, todo, timeout=None):
|
|
708
|
+
try:
|
|
709
|
+
proxy = await self.getAhaSvcProxy(svcdef, timeout=timeout)
|
|
710
|
+
meth = getattr(proxy, todo[0])
|
|
711
|
+
async for item in s_common.waitgenr(meth(*todo[1], **todo[2]), timeout=timeout):
|
|
712
|
+
yield item
|
|
713
|
+
except Exception as e:
|
|
714
|
+
# in case proxy construction fails
|
|
715
|
+
yield (False, s_common.excinfo(e))
|
|
716
|
+
|
|
717
|
+
async def getAhaSvcsByIden(self, iden, online=True, skiprun=None):
|
|
718
|
+
|
|
719
|
+
runs = set()
|
|
720
|
+
async for svcdef in self.getAhaSvcs():
|
|
721
|
+
await asyncio.sleep(0)
|
|
722
|
+
|
|
723
|
+
# TODO services by iden indexes (SYN-8467)
|
|
724
|
+
if svcdef['svcinfo'].get('iden') != iden:
|
|
725
|
+
continue
|
|
726
|
+
|
|
727
|
+
if online and svcdef['svcinfo'].get('online') is None:
|
|
728
|
+
continue
|
|
729
|
+
|
|
730
|
+
svcrun = svcdef['svcinfo'].get('run')
|
|
731
|
+
if svcrun in runs:
|
|
732
|
+
continue
|
|
733
|
+
|
|
734
|
+
if skiprun == svcrun:
|
|
735
|
+
continue
|
|
736
|
+
|
|
737
|
+
runs.add(svcrun)
|
|
738
|
+
yield svcdef
|
|
739
|
+
|
|
740
|
+
def getAhaSvcUrl(self, svcdef, user='root'):
|
|
741
|
+
svcfull = svcdef.get('name')
|
|
742
|
+
svcnetw = svcdef.get('svcnetw')
|
|
743
|
+
host = svcdef['svcinfo']['urlinfo']['host']
|
|
744
|
+
port = svcdef['svcinfo']['urlinfo']['port']
|
|
745
|
+
return f'ssl://{host}:{port}?hostname={svcfull}&certname={user}@{svcnetw}'
|
|
746
|
+
|
|
747
|
+
async def callAhaPeerApi(self, iden, todo, timeout=None, skiprun=None):
|
|
748
|
+
|
|
749
|
+
if not self.isactive:
|
|
750
|
+
proxy = await self.nexsroot.client.proxy(timeout=timeout)
|
|
751
|
+
async for item in proxy.callAhaPeerApi(iden, todo, timeout=timeout, skiprun=skiprun):
|
|
752
|
+
yield item
|
|
753
|
+
|
|
754
|
+
queue = asyncio.Queue()
|
|
755
|
+
async with await s_base.Base.anit() as base:
|
|
756
|
+
|
|
757
|
+
async def call(svcdef):
|
|
758
|
+
svcfull = svcdef.get('name')
|
|
759
|
+
await queue.put((svcfull, await self._callAhaSvcApi(svcdef, todo, timeout=timeout)))
|
|
760
|
+
|
|
761
|
+
count = 0
|
|
762
|
+
async for svcdef in self.getAhaSvcsByIden(iden, skiprun=skiprun):
|
|
763
|
+
count += 1
|
|
764
|
+
base.schedCoro(call(svcdef))
|
|
765
|
+
|
|
766
|
+
for i in range(count):
|
|
767
|
+
yield await queue.get()
|
|
768
|
+
|
|
769
|
+
async def callAhaPeerGenr(self, iden, todo, timeout=None, skiprun=None):
|
|
770
|
+
|
|
771
|
+
if not self.isactive:
|
|
772
|
+
proxy = await self.nexsroot.client.proxy(timeout=timeout)
|
|
773
|
+
async for item in proxy.callAhaPeerGenr(iden, todo, timeout=timeout, skiprun=skiprun):
|
|
774
|
+
yield item
|
|
775
|
+
|
|
776
|
+
queue = asyncio.Queue()
|
|
777
|
+
async with await s_base.Base.anit() as base:
|
|
778
|
+
|
|
779
|
+
async def call(svcdef):
|
|
780
|
+
svcfull = svcdef.get('name')
|
|
781
|
+
try:
|
|
782
|
+
async for item in self._callAhaSvcGenr(svcdef, todo, timeout=timeout):
|
|
783
|
+
await queue.put((svcfull, item))
|
|
784
|
+
finally:
|
|
785
|
+
await queue.put(None)
|
|
786
|
+
|
|
787
|
+
count = 0
|
|
788
|
+
async for svcdef in self.getAhaSvcsByIden(iden, skiprun=skiprun):
|
|
789
|
+
count += 1
|
|
790
|
+
base.schedCoro(call(svcdef))
|
|
791
|
+
|
|
792
|
+
while count > 0:
|
|
793
|
+
|
|
794
|
+
item = await queue.get()
|
|
795
|
+
if item is None:
|
|
796
|
+
count -= 1
|
|
797
|
+
continue
|
|
798
|
+
|
|
799
|
+
yield item
|
|
800
|
+
|
|
801
|
+
async def _finiSvcClients(self):
|
|
802
|
+
for client in list(self.clients.values()):
|
|
803
|
+
await client.fini()
|
|
804
|
+
|
|
805
|
+
async def initServicePassive(self):
|
|
806
|
+
await self._finiSvcClients()
|
|
807
|
+
|
|
685
808
|
async def initServiceRuntime(self):
|
|
686
809
|
|
|
810
|
+
self.clients = {}
|
|
811
|
+
self.onfini(self._finiSvcClients)
|
|
812
|
+
|
|
687
813
|
self.addActiveCoro(self._clearInactiveSessions)
|
|
688
814
|
|
|
689
815
|
if self.isactive:
|
|
@@ -897,6 +1023,31 @@ class AhaCell(s_cell.Cell):
|
|
|
897
1023
|
await self.fire('aha:svcadd', svcinfo=svcinfo)
|
|
898
1024
|
await self.fire(f'aha:svcadd:{svcfull}', svcinfo=svcinfo)
|
|
899
1025
|
|
|
1026
|
+
async def getAhaSvcProxy(self, svcdef, timeout=None):
|
|
1027
|
+
|
|
1028
|
+
client = await self.getAhaSvcClient(svcdef)
|
|
1029
|
+
if client is None:
|
|
1030
|
+
return None
|
|
1031
|
+
|
|
1032
|
+
return await client.proxy(timeout=timeout)
|
|
1033
|
+
|
|
1034
|
+
async def getAhaSvcClient(self, svcdef):
|
|
1035
|
+
|
|
1036
|
+
svcfull = svcdef.get('name')
|
|
1037
|
+
|
|
1038
|
+
client = self.clients.get(svcfull)
|
|
1039
|
+
if client is not None:
|
|
1040
|
+
return client
|
|
1041
|
+
|
|
1042
|
+
svcurl = self.getAhaSvcUrl(svcdef)
|
|
1043
|
+
|
|
1044
|
+
client = self.clients[svcfull] = await s_telepath.ClientV2.anit(svcurl)
|
|
1045
|
+
async def fini():
|
|
1046
|
+
self.clients.pop(svcfull, None)
|
|
1047
|
+
|
|
1048
|
+
client.onfini(fini)
|
|
1049
|
+
return client
|
|
1050
|
+
|
|
900
1051
|
def _getAhaName(self, name):
|
|
901
1052
|
# the modern version of names is absolute or ...
|
|
902
1053
|
if name.endswith('...'):
|
|
@@ -1066,6 +1217,10 @@ class AhaCell(s_cell.Cell):
|
|
|
1066
1217
|
logger.info(f'Set [{svcfull}] offline.',
|
|
1067
1218
|
extra=await self.getLogExtra(name=svcname, netw=svcnetw))
|
|
1068
1219
|
|
|
1220
|
+
client = self.clients.pop(svcfull, None)
|
|
1221
|
+
if client is not None:
|
|
1222
|
+
await client.fini()
|
|
1223
|
+
|
|
1069
1224
|
async def getAhaSvc(self, name, filters=None):
|
|
1070
1225
|
|
|
1071
1226
|
name = self._getAhaName(name)
|
synapse/lib/cell.py
CHANGED
|
@@ -83,6 +83,8 @@ permnames = {
|
|
|
83
83
|
PERM_ADMIN: 'admin',
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
feat_aha_callpeers_v1 = ('callpeers', 1)
|
|
87
|
+
|
|
86
88
|
diskspace = "Insufficient free space on disk."
|
|
87
89
|
|
|
88
90
|
def adminapi(log=False):
|
|
@@ -435,6 +437,19 @@ class CellApi(s_base.Base):
|
|
|
435
437
|
async def kill(self, iden):
|
|
436
438
|
return await self.cell.kill(self.user, iden)
|
|
437
439
|
|
|
440
|
+
@adminapi()
|
|
441
|
+
async def getTasks(self, peers=True, timeout=None):
|
|
442
|
+
async for task in self.cell.getTasks(peers=peers, timeout=timeout):
|
|
443
|
+
yield task
|
|
444
|
+
|
|
445
|
+
@adminapi()
|
|
446
|
+
async def getTask(self, iden, peers=True, timeout=None):
|
|
447
|
+
return await self.cell.getTask(iden, peers=peers, timeout=timeout)
|
|
448
|
+
|
|
449
|
+
@adminapi()
|
|
450
|
+
async def killTask(self, iden, peers=True, timeout=None):
|
|
451
|
+
return await self.cell.killTask(iden, peers=peers, timeout=timeout)
|
|
452
|
+
|
|
438
453
|
@adminapi(log=True)
|
|
439
454
|
async def behold(self):
|
|
440
455
|
'''
|
|
@@ -765,8 +780,8 @@ class CellApi(s_base.Base):
|
|
|
765
780
|
return await self.cell.saveHiveTree(path=path)
|
|
766
781
|
|
|
767
782
|
@adminapi()
|
|
768
|
-
async def getNexusChanges(self, offs, tellready=False):
|
|
769
|
-
async for item in self.cell.getNexusChanges(offs, tellready=tellready):
|
|
783
|
+
async def getNexusChanges(self, offs, tellready=False, wait=True):
|
|
784
|
+
async for item in self.cell.getNexusChanges(offs, tellready=tellready, wait=wait):
|
|
770
785
|
yield item
|
|
771
786
|
|
|
772
787
|
@adminapi()
|
|
@@ -1165,6 +1180,11 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
1165
1180
|
self.netready = asyncio.Event()
|
|
1166
1181
|
|
|
1167
1182
|
self.conf = self._initCellConf(conf)
|
|
1183
|
+
self.features = {
|
|
1184
|
+
'tellready': 1,
|
|
1185
|
+
'dynmirror': 1,
|
|
1186
|
+
'tasks': 1,
|
|
1187
|
+
}
|
|
1168
1188
|
|
|
1169
1189
|
self.minfree = self.conf.get('limit:disk:free')
|
|
1170
1190
|
if self.minfree is not None:
|
|
@@ -2382,8 +2402,8 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
2382
2402
|
async def initServicePassive(self): # pragma: no cover
|
|
2383
2403
|
pass
|
|
2384
2404
|
|
|
2385
|
-
async def getNexusChanges(self, offs, tellready=False):
|
|
2386
|
-
async for item in self.nexsroot.iter(offs, tellready=tellready):
|
|
2405
|
+
async def getNexusChanges(self, offs, tellready=False, wait=True):
|
|
2406
|
+
async for item in self.nexsroot.iter(offs, tellready=tellready, wait=wait):
|
|
2387
2407
|
yield item
|
|
2388
2408
|
|
|
2389
2409
|
def _reqBackDirn(self, name):
|
|
@@ -4414,6 +4434,111 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4414
4434
|
|
|
4415
4435
|
return retn
|
|
4416
4436
|
|
|
4437
|
+
async def getAhaProxy(self, timeout=None, feats=None):
|
|
4438
|
+
|
|
4439
|
+
if self.ahaclient is None:
|
|
4440
|
+
return
|
|
4441
|
+
|
|
4442
|
+
proxy = await self.ahaclient.proxy(timeout=timeout)
|
|
4443
|
+
if proxy is None:
|
|
4444
|
+
logger.warning('AHA client connection failed.')
|
|
4445
|
+
return
|
|
4446
|
+
|
|
4447
|
+
if feats is not None:
|
|
4448
|
+
for name, vers in feats:
|
|
4449
|
+
if not proxy._hasTeleFeat(name, vers):
|
|
4450
|
+
logger.warning(f'AHA server does not support feature: {name} >= {vers}')
|
|
4451
|
+
return None
|
|
4452
|
+
|
|
4453
|
+
return proxy
|
|
4454
|
+
|
|
4455
|
+
async def callPeerApi(self, todo, timeout=None):
|
|
4456
|
+
'''
|
|
4457
|
+
Yield responses from our peers via the AHA gather call API.
|
|
4458
|
+
'''
|
|
4459
|
+
proxy = await self.getAhaProxy(timeout=timeout, feats=(feat_aha_callpeers_v1,))
|
|
4460
|
+
if proxy is None:
|
|
4461
|
+
return
|
|
4462
|
+
|
|
4463
|
+
async for item in proxy.callAhaPeerApi(self.iden, todo, timeout=timeout, skiprun=self.runid):
|
|
4464
|
+
yield item
|
|
4465
|
+
|
|
4466
|
+
async def callPeerGenr(self, todo, timeout=None):
|
|
4467
|
+
'''
|
|
4468
|
+
Yield responses from invoking a generator via the AHA gather API.
|
|
4469
|
+
'''
|
|
4470
|
+
proxy = await self.getAhaProxy(timeout=timeout, feats=(feat_aha_callpeers_v1,))
|
|
4471
|
+
if proxy is None:
|
|
4472
|
+
return
|
|
4473
|
+
|
|
4474
|
+
async for item in proxy.callAhaPeerGenr(self.iden, todo, timeout=timeout, skiprun=self.runid):
|
|
4475
|
+
yield item
|
|
4476
|
+
|
|
4477
|
+
async def getTasks(self, peers=True, timeout=None):
|
|
4478
|
+
|
|
4479
|
+
for task in self.boss.ps():
|
|
4480
|
+
|
|
4481
|
+
item = task.pack()
|
|
4482
|
+
item['service'] = self.ahasvcname
|
|
4483
|
+
|
|
4484
|
+
yield item
|
|
4485
|
+
|
|
4486
|
+
if not peers:
|
|
4487
|
+
return
|
|
4488
|
+
|
|
4489
|
+
todo = s_common.todo('getTasks', peers=False)
|
|
4490
|
+
# we can ignore the yielded aha names because we embed it in the task
|
|
4491
|
+
async for (ahasvc, (ok, retn)) in self.callPeerGenr(todo, timeout=timeout):
|
|
4492
|
+
|
|
4493
|
+
if not ok: # pragma: no cover
|
|
4494
|
+
logger.warning(f'getTasks() on {ahasvc} failed: {retn}')
|
|
4495
|
+
continue
|
|
4496
|
+
|
|
4497
|
+
yield retn
|
|
4498
|
+
|
|
4499
|
+
async def getTask(self, iden, peers=True, timeout=None):
|
|
4500
|
+
|
|
4501
|
+
task = self.boss.get(iden)
|
|
4502
|
+
if task is not None:
|
|
4503
|
+
item = task.pack()
|
|
4504
|
+
item['service'] = self.ahasvcname
|
|
4505
|
+
return item
|
|
4506
|
+
|
|
4507
|
+
if not peers:
|
|
4508
|
+
return
|
|
4509
|
+
|
|
4510
|
+
todo = s_common.todo('getTask', iden, peers=False, timeout=timeout)
|
|
4511
|
+
async for ahasvc, (ok, retn) in self.callPeerApi(todo, timeout=timeout):
|
|
4512
|
+
|
|
4513
|
+
if not ok: # pragma: no cover
|
|
4514
|
+
logger.warning(f'getTask() on {ahasvc} failed: {retn}')
|
|
4515
|
+
continue
|
|
4516
|
+
|
|
4517
|
+
if retn is not None:
|
|
4518
|
+
return retn
|
|
4519
|
+
|
|
4520
|
+
async def killTask(self, iden, peers=True, timeout=None):
|
|
4521
|
+
|
|
4522
|
+
task = self.boss.get(iden)
|
|
4523
|
+
if task is not None:
|
|
4524
|
+
await task.kill()
|
|
4525
|
+
return True
|
|
4526
|
+
|
|
4527
|
+
if not peers:
|
|
4528
|
+
return False
|
|
4529
|
+
|
|
4530
|
+
todo = s_common.todo('killTask', iden, peers=False, timeout=timeout)
|
|
4531
|
+
async for ahasvc, (ok, retn) in self.callPeerApi(todo, timeout=timeout):
|
|
4532
|
+
|
|
4533
|
+
if not ok: # pragma: no cover
|
|
4534
|
+
logger.warning(f'killTask() on {ahasvc} failed: {retn}')
|
|
4535
|
+
continue
|
|
4536
|
+
|
|
4537
|
+
if retn:
|
|
4538
|
+
return True
|
|
4539
|
+
|
|
4540
|
+
return False
|
|
4541
|
+
|
|
4417
4542
|
async def kill(self, user, iden):
|
|
4418
4543
|
perm = ('task', 'del')
|
|
4419
4544
|
isallowed = await self.isUserAllowed(user.iden, perm)
|
|
@@ -4488,13 +4613,13 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4488
4613
|
'https': self.https_listeners,
|
|
4489
4614
|
}
|
|
4490
4615
|
},
|
|
4491
|
-
'features':
|
|
4492
|
-
'tellready': True,
|
|
4493
|
-
'dynmirror': True,
|
|
4494
|
-
},
|
|
4616
|
+
'features': self.features,
|
|
4495
4617
|
}
|
|
4496
4618
|
return ret
|
|
4497
4619
|
|
|
4620
|
+
async def getTeleFeats(self):
|
|
4621
|
+
return dict(self.features)
|
|
4622
|
+
|
|
4498
4623
|
async def getSystemInfo(self):
|
|
4499
4624
|
'''
|
|
4500
4625
|
Get info about the system in which the cell is running
|
synapse/lib/jsonstor.py
CHANGED
synapse/lib/modelrev.py
CHANGED
|
@@ -13,7 +13,7 @@ import synapse.models.infotech as s_infotech
|
|
|
13
13
|
|
|
14
14
|
logger = logging.getLogger(__name__)
|
|
15
15
|
|
|
16
|
-
maxvers = (0, 2,
|
|
16
|
+
maxvers = (0, 2, 33)
|
|
17
17
|
|
|
18
18
|
class ModelRev:
|
|
19
19
|
|
|
@@ -51,6 +51,7 @@ class ModelRev:
|
|
|
51
51
|
((0, 2, 30), self.revModel_0_2_30),
|
|
52
52
|
((0, 2, 31), self.revModel_0_2_31),
|
|
53
53
|
((0, 2, 32), self.revModel_0_2_32),
|
|
54
|
+
((0, 2, 33), self.revModel_0_2_33),
|
|
54
55
|
)
|
|
55
56
|
|
|
56
57
|
async def _uniqSortArray(self, todoprops, layers):
|
|
@@ -820,6 +821,9 @@ class ModelRev:
|
|
|
820
821
|
await self._normPropValu(layers, 'transport:air:craft:model')
|
|
821
822
|
await self._normPropValu(layers, 'transport:sea:vessel:model')
|
|
822
823
|
|
|
824
|
+
async def revModel_0_2_33(self, layers):
|
|
825
|
+
await self._propToForm(layers, 'transport:sea:vessel:name', 'entity:name')
|
|
826
|
+
|
|
823
827
|
async def runStorm(self, text, opts=None):
|
|
824
828
|
'''
|
|
825
829
|
Run storm code in a schedcoro and log the output messages.
|
synapse/lib/nexus.py
CHANGED
|
@@ -413,7 +413,7 @@ class NexsRoot(s_base.Base):
|
|
|
413
413
|
|
|
414
414
|
return await func(nexus, *args, **kwargs)
|
|
415
415
|
|
|
416
|
-
async def iter(self, offs: int, tellready=False) -> AsyncIterator[Any]:
|
|
416
|
+
async def iter(self, offs: int, tellready=False, wait=True) -> AsyncIterator[Any]:
|
|
417
417
|
'''
|
|
418
418
|
Returns an iterator of change entries in the log
|
|
419
419
|
'''
|
|
@@ -434,6 +434,9 @@ class NexsRoot(s_base.Base):
|
|
|
434
434
|
if tellready:
|
|
435
435
|
yield None
|
|
436
436
|
|
|
437
|
+
if not wait:
|
|
438
|
+
return
|
|
439
|
+
|
|
437
440
|
async with self.getChangeDist(maxoffs) as dist:
|
|
438
441
|
async for item in dist:
|
|
439
442
|
if self.isfini:
|
synapse/lib/reflect.py
CHANGED
|
@@ -87,17 +87,16 @@ def getShareInfo(item):
|
|
|
87
87
|
if not callable(attr):
|
|
88
88
|
continue
|
|
89
89
|
|
|
90
|
+
meths[name] = meth = {}
|
|
91
|
+
|
|
90
92
|
# We know we can cleanly unwrap these functions
|
|
91
93
|
# for asyncgenerator inspection.
|
|
92
94
|
wrapped = getattr(attr, '__syn_wrapped__', None)
|
|
93
95
|
if wrapped in unwraps:
|
|
94
|
-
|
|
95
|
-
if inspect.isasyncgenfunction(real):
|
|
96
|
-
meths[name] = {'genr': True}
|
|
97
|
-
continue
|
|
96
|
+
attr = inspect.unwrap(attr)
|
|
98
97
|
|
|
99
98
|
if inspect.isasyncgenfunction(attr):
|
|
100
|
-
|
|
99
|
+
meth['genr'] = True
|
|
101
100
|
|
|
102
101
|
try:
|
|
103
102
|
setattr(item, key, info)
|