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/lib/snap.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import sys
|
|
3
4
|
import types
|
|
4
5
|
import asyncio
|
|
5
6
|
import logging
|
|
@@ -318,7 +319,7 @@ class ProtoNode:
|
|
|
318
319
|
|
|
319
320
|
if prop.locked:
|
|
320
321
|
mesg = f'Tagprop {name} is locked.'
|
|
321
|
-
return await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg)
|
|
322
|
+
return await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg, prop=name)
|
|
322
323
|
|
|
323
324
|
try:
|
|
324
325
|
norm, info = prop.type.norm(valu)
|
|
@@ -348,14 +349,14 @@ class ProtoNode:
|
|
|
348
349
|
|
|
349
350
|
if prop.locked:
|
|
350
351
|
mesg = f'Prop {prop.full} is locked due to deprecation.'
|
|
351
|
-
await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg)
|
|
352
|
+
await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg, prop=prop.full)
|
|
352
353
|
return False
|
|
353
354
|
|
|
354
355
|
if isinstance(prop.type, s_types.Array):
|
|
355
356
|
arrayform = self.ctx.snap.core.model.form(prop.type.arraytype.name)
|
|
356
357
|
if arrayform is not None and arrayform.locked:
|
|
357
358
|
mesg = f'Prop {prop.full} is locked due to deprecation.'
|
|
358
|
-
await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg)
|
|
359
|
+
await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg, prop=prop.full)
|
|
359
360
|
return False
|
|
360
361
|
|
|
361
362
|
if norminfo is None:
|
|
@@ -375,7 +376,7 @@ class ProtoNode:
|
|
|
375
376
|
ndefform = self.ctx.snap.core.model.form(valu[0])
|
|
376
377
|
if ndefform.locked:
|
|
377
378
|
mesg = f'Prop {prop.full} is locked due to deprecation.'
|
|
378
|
-
await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg)
|
|
379
|
+
await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg, prop=prop.full)
|
|
379
380
|
return False
|
|
380
381
|
|
|
381
382
|
curv = self.get(prop.name)
|
|
@@ -414,7 +415,8 @@ class ProtoNode:
|
|
|
414
415
|
if propsubs is not None:
|
|
415
416
|
for subname, subvalu in propsubs.items():
|
|
416
417
|
full = f'{prop.name}:{subname}'
|
|
417
|
-
|
|
418
|
+
subprop = self.form.props.get(full)
|
|
419
|
+
if subprop is not None and not subprop.locked:
|
|
418
420
|
await self.set(full, subvalu)
|
|
419
421
|
|
|
420
422
|
propadds = norminfo.get('adds')
|
|
@@ -445,7 +447,8 @@ class ProtoNode:
|
|
|
445
447
|
if propsubs is not None:
|
|
446
448
|
for subname, subvalu in propsubs.items():
|
|
447
449
|
full = f'{prop.name}:{subname}'
|
|
448
|
-
|
|
450
|
+
subprop = self.form.props.get(full)
|
|
451
|
+
if subprop is not None and not subprop.locked:
|
|
449
452
|
ops.append(self.getSetOps(full, subvalu))
|
|
450
453
|
|
|
451
454
|
propadds = norminfo.get('adds')
|
|
@@ -487,7 +490,7 @@ class SnapEditor:
|
|
|
487
490
|
|
|
488
491
|
if form.locked:
|
|
489
492
|
mesg = f'Form {form.full} is locked due to deprecation for valu={valu}.'
|
|
490
|
-
return await self.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg)
|
|
493
|
+
return await self.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg, prop=form.full)
|
|
491
494
|
|
|
492
495
|
if norminfo is None:
|
|
493
496
|
try:
|
|
@@ -1615,6 +1618,10 @@ class Snap(s_base.Base):
|
|
|
1615
1618
|
return tagnode
|
|
1616
1619
|
|
|
1617
1620
|
async def _raiseOnStrict(self, ctor, mesg, **info):
|
|
1621
|
+
if __debug__:
|
|
1622
|
+
if issubclass(ctor, s_exc.IsDeprLocked):
|
|
1623
|
+
sys.audit('synapse.exc.IsDeprLocked', (mesg, info))
|
|
1624
|
+
|
|
1618
1625
|
if self.strict:
|
|
1619
1626
|
raise ctor(mesg=mesg, **info)
|
|
1620
1627
|
await self.warn(mesg)
|
synapse/lib/stormlib/aha.py
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import textwrap
|
|
2
|
+
|
|
1
3
|
import synapse.exc as s_exc
|
|
4
|
+
import synapse.common as s_common
|
|
2
5
|
import synapse.lib.stormtypes as s_stormtypes
|
|
3
6
|
|
|
4
7
|
@s_stormtypes.registry.registerLib
|
|
@@ -49,6 +52,80 @@ class AhaLib(s_stormtypes.Lib):
|
|
|
49
52
|
'type': {'type': 'function', '_funcname': '_methAhaList', 'args': (),
|
|
50
53
|
'returns': {'name': 'Yields', 'type': 'list',
|
|
51
54
|
'desc': 'The AHA service dictionaries.', }}},
|
|
55
|
+
{'name': 'callPeerApi', 'desc': '''Call an API on all peers (leader and mirrors) of an AHA service and yield the responses from each.
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
Call getCellInfo on an AHA service::
|
|
59
|
+
|
|
60
|
+
$todo = $lib.utils.todo('getCellInfo')
|
|
61
|
+
for $info in $lib.aha.callPeerApi(cortex..., $todo) {
|
|
62
|
+
$lib.print($info)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Call getCellInfo on an AHA service, skipping the invoking service::
|
|
66
|
+
|
|
67
|
+
$todo = $lib.utils.todo('getCellInfo')
|
|
68
|
+
for $info in $lib.aha.callPeerApi(cortex..., $todo, skiprun=$lib.cell.getCellInfo().cell.run) {
|
|
69
|
+
$lib.print($info)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
Call method with arguments::
|
|
73
|
+
|
|
74
|
+
$todo = $lib.utils.todo(('method', ([1, 2]), ({'foo': 'bar'})))
|
|
75
|
+
for $info in $lib.aha.callPeerApi(cortex..., $todo) {
|
|
76
|
+
$lib.print($info)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
''',
|
|
80
|
+
'type': {'type': 'function', '_funcname': '_methCallPeerApi',
|
|
81
|
+
'args': (
|
|
82
|
+
{'name': 'svcname', 'type': 'str',
|
|
83
|
+
'desc': 'The name of the AHA service to call. It is easiest to use the relative name of a service, ending with "...".', },
|
|
84
|
+
{'name': 'todo', 'type': 'list',
|
|
85
|
+
'desc': 'The todo tuple (name, args, kwargs).'},
|
|
86
|
+
{'name': 'timeout', 'type': 'int', 'default': None,
|
|
87
|
+
'desc': 'Optional timeout in seconds.'},
|
|
88
|
+
{'name': 'skiprun', 'type': 'str', 'default': None,
|
|
89
|
+
'desc': '''Optional run ID argument that allows skipping results from a specific service run ID.
|
|
90
|
+
This is most often used to omit the invoking service from the results, ensuring that only responses from other services are included.
|
|
91
|
+
'''},
|
|
92
|
+
),
|
|
93
|
+
'returns': {'name': 'yields', 'type': 'list',
|
|
94
|
+
'desc': 'Yields the results of the API calls as tuples of (svcname, (ok, info)).', }}},
|
|
95
|
+
{'name': 'callPeerGenr', 'desc': '''Call a generator API on all peers (leader and mirrors) of an AHA service and yield the responses from each.
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
Call getNexusChanges on an AHA service::
|
|
99
|
+
|
|
100
|
+
$todo = $lib.utils.todo('getNexusChanges', (0), wait=$lib.false)
|
|
101
|
+
for $info in $lib.aha.callPeerGenr(cortex..., $todo) {
|
|
102
|
+
$lib.print($info)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
Call getNexusChanges on an AHA service, skipping the invoking service::
|
|
106
|
+
|
|
107
|
+
$todo = $lib.utils.todo('getNexusChanges', (0), wait=$lib.false)
|
|
108
|
+
for $info in $lib.aha.callPeerGenr(cortex..., $todo, skiprun=$lib.cell.getCellInfo().cell.run) {
|
|
109
|
+
$lib.print($info)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
''',
|
|
113
|
+
'type': {'type': 'function', '_funcname': '_methCallPeerGenr',
|
|
114
|
+
'args': (
|
|
115
|
+
{'name': 'svcname', 'type': 'str',
|
|
116
|
+
'desc': 'The name of the AHA service to call. It is easiest to use the relative name of a service, ending with "...".', },
|
|
117
|
+
{'name': 'todo', 'type': 'list',
|
|
118
|
+
'desc': 'The todo tuple (name, args, kwargs).'},
|
|
119
|
+
{'name': 'timeout', 'type': 'int', 'default': None,
|
|
120
|
+
'desc': 'Optional timeout in seconds.'},
|
|
121
|
+
{'name': 'skiprun', 'type': 'str', 'default': None,
|
|
122
|
+
'desc': '''Optional run ID argument that allows skipping results from a specific service run ID.
|
|
123
|
+
This is most often used to omit the invoking service from the results, ensuring that only responses from other services are included.
|
|
124
|
+
'''},
|
|
125
|
+
),
|
|
126
|
+
'returns': {'name': 'yields', 'type': 'list',
|
|
127
|
+
'desc': 'Yields the results of the API calls as tuples containing (svcname, (ok, info)).', }}}
|
|
128
|
+
|
|
52
129
|
)
|
|
53
130
|
_storm_lib_path = ('aha',)
|
|
54
131
|
def getObjLocals(self):
|
|
@@ -56,6 +133,8 @@ class AhaLib(s_stormtypes.Lib):
|
|
|
56
133
|
'del': self._methAhaDel,
|
|
57
134
|
'get': self._methAhaGet,
|
|
58
135
|
'list': self._methAhaList,
|
|
136
|
+
'callPeerApi': self._methCallPeerApi,
|
|
137
|
+
'callPeerGenr': self._methCallPeerGenr,
|
|
59
138
|
}
|
|
60
139
|
|
|
61
140
|
@s_stormtypes.stormfunc(readonly=True)
|
|
@@ -85,6 +164,62 @@ class AhaLib(s_stormtypes.Lib):
|
|
|
85
164
|
proxy = await self.runt.snap.core.reqAhaProxy()
|
|
86
165
|
return await proxy.getAhaSvc(svcname, filters=filters)
|
|
87
166
|
|
|
167
|
+
async def _methCallPeerApi(self, svcname, todo, timeout=None, skiprun=None):
|
|
168
|
+
'''
|
|
169
|
+
Call an API on an AHA service.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
svcname (str): The name of the AHA service to call.
|
|
173
|
+
todo (list): The todo tuple from $lib.utils.todo().
|
|
174
|
+
timeout (int): Optional timeout in seconds.
|
|
175
|
+
skiprun (str): Optional run ID argument allows skipping self-enumeration.
|
|
176
|
+
'''
|
|
177
|
+
svcname = await s_stormtypes.tostr(svcname)
|
|
178
|
+
todo = await s_stormtypes.toprim(todo)
|
|
179
|
+
timeout = await s_stormtypes.toint(timeout, noneok=True)
|
|
180
|
+
skiprun = await s_stormtypes.tostr(skiprun, noneok=True)
|
|
181
|
+
|
|
182
|
+
proxy = await self.runt.snap.core.reqAhaProxy()
|
|
183
|
+
svc = await proxy.getAhaSvc(svcname)
|
|
184
|
+
if svc is None:
|
|
185
|
+
raise s_exc.NoSuchName(mesg=f'No AHA service found for {svcname}')
|
|
186
|
+
|
|
187
|
+
svcinfo = svc.get('svcinfo')
|
|
188
|
+
svciden = svcinfo.get('iden')
|
|
189
|
+
if svciden is None:
|
|
190
|
+
raise s_exc.NoSuchName(mesg=f'Service {svcname} has no iden')
|
|
191
|
+
|
|
192
|
+
async for svcname, (ok, info) in proxy.callAhaPeerApi(svciden, todo, timeout=timeout, skiprun=skiprun):
|
|
193
|
+
yield (svcname, (ok, info))
|
|
194
|
+
|
|
195
|
+
async def _methCallPeerGenr(self, svcname, todo, timeout=None, skiprun=None):
|
|
196
|
+
'''
|
|
197
|
+
Call a generator API on an AHA service.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
svcname (str): The name of the AHA service to call.
|
|
201
|
+
todo (list): The todo tuple from $lib.utils.todo().
|
|
202
|
+
timeout (int): Optional timeout in seconds.
|
|
203
|
+
skiprun (str): Optional run ID argument allows skipping self-enumeration.
|
|
204
|
+
'''
|
|
205
|
+
svcname = await s_stormtypes.tostr(svcname)
|
|
206
|
+
todo = await s_stormtypes.toprim(todo)
|
|
207
|
+
timeout = await s_stormtypes.toint(timeout, noneok=True)
|
|
208
|
+
skiprun = await s_stormtypes.tostr(skiprun, noneok=True)
|
|
209
|
+
|
|
210
|
+
proxy = await self.runt.snap.core.reqAhaProxy()
|
|
211
|
+
svc = await proxy.getAhaSvc(svcname)
|
|
212
|
+
if svc is None:
|
|
213
|
+
raise s_exc.NoSuchName(mesg=f'No AHA service found for {svcname}')
|
|
214
|
+
|
|
215
|
+
svcinfo = svc.get('svcinfo')
|
|
216
|
+
svciden = svcinfo.get('iden')
|
|
217
|
+
if svciden is None:
|
|
218
|
+
raise s_exc.NoSuchName(mesg=f'Service {svcname} has no iden')
|
|
219
|
+
|
|
220
|
+
async for svcname, (ok, info) in proxy.callAhaPeerGenr(svciden, todo, timeout=timeout, skiprun=skiprun):
|
|
221
|
+
yield (svcname, (ok, info))
|
|
222
|
+
|
|
88
223
|
@s_stormtypes.registry.registerLib
|
|
89
224
|
class AhaPoolLib(s_stormtypes.Lib):
|
|
90
225
|
'''
|
|
@@ -531,5 +666,220 @@ The ready column indicates that a service has entered into the realtime change w
|
|
|
531
666
|
}
|
|
532
667
|
}
|
|
533
668
|
'''
|
|
534
|
-
}
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
'name': 'aha.svc.mirror',
|
|
672
|
+
'descr': textwrap.dedent('''\
|
|
673
|
+
Query the AHA services and their mirror relationships.
|
|
674
|
+
|
|
675
|
+
Note: non-mirror services are not displayed.
|
|
676
|
+
'''),
|
|
677
|
+
'cmdargs': (
|
|
678
|
+
('--timeout', {'help': 'The timeout in seconds for individual service API calls.',
|
|
679
|
+
'default': 10, 'type': 'int'}),
|
|
680
|
+
('--wait', {'help': 'Whether to wait for the mirrors to sync.',
|
|
681
|
+
'action': 'store_true'}),
|
|
682
|
+
),
|
|
683
|
+
'storm': '''
|
|
684
|
+
init {
|
|
685
|
+
$conf = ({
|
|
686
|
+
"columns": [
|
|
687
|
+
{"name": "name", "width": 40},
|
|
688
|
+
{"name": "role", "width": 9},
|
|
689
|
+
{"name": "online", "width": 7},
|
|
690
|
+
{"name": "ready", "width": 6},
|
|
691
|
+
{"name": "host", "width": 16},
|
|
692
|
+
{"name": "port", "width": 8},
|
|
693
|
+
{"name": "version", "width": 12},
|
|
694
|
+
{"name": "nexus idx", "width": 10},
|
|
695
|
+
],
|
|
696
|
+
"separators": {
|
|
697
|
+
"row:outline": false,
|
|
698
|
+
"column:outline": false,
|
|
699
|
+
"header:row": "#",
|
|
700
|
+
"data:row": "",
|
|
701
|
+
"column": "",
|
|
702
|
+
},
|
|
703
|
+
})
|
|
704
|
+
$printer = $lib.tabular.printer($conf)
|
|
705
|
+
$timeout = $cmdopts.timeout
|
|
706
|
+
$wait = $cmdopts.wait
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function get_cell_infos(vname, timeout) {
|
|
710
|
+
$cell_infos = ({})
|
|
711
|
+
$todo = $lib.utils.todo('getCellInfo')
|
|
712
|
+
for $info in $lib.aha.callPeerApi($vname, $todo, timeout=$timeout) {
|
|
713
|
+
$svcname = $info.0
|
|
714
|
+
($ok, $info) = $info.1
|
|
715
|
+
if $ok {
|
|
716
|
+
$cell_infos.$svcname = $info
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return($cell_infos)
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function build_status_list(members, cell_infos) {
|
|
723
|
+
$group_status = ()
|
|
724
|
+
for $svc in $members {
|
|
725
|
+
$svcinfo = $svc.svcinfo
|
|
726
|
+
$svcname = $svc.name
|
|
727
|
+
$status = ({
|
|
728
|
+
'name': $svcname,
|
|
729
|
+
'role': '<unknown>',
|
|
730
|
+
'online': $lib.dict.has($svcinfo, 'online'),
|
|
731
|
+
'ready': $svcinfo.ready,
|
|
732
|
+
'host': $svcinfo.urlinfo.host,
|
|
733
|
+
'port': $svcinfo.urlinfo.port,
|
|
734
|
+
'version': '<unknown>',
|
|
735
|
+
'nexs_indx': (0)
|
|
736
|
+
})
|
|
737
|
+
if ($cell_infos.$svcname) {
|
|
738
|
+
$info = $cell_infos.$svcname
|
|
739
|
+
$cell_info = $info.cell
|
|
740
|
+
$status.nexs_indx = $cell_info.nexsindx
|
|
741
|
+
if ($cell_info.uplink) {
|
|
742
|
+
$status.role = 'follower'
|
|
743
|
+
} else {
|
|
744
|
+
$status.role = 'leader'
|
|
745
|
+
}
|
|
746
|
+
$status.version = $info.synapse.verstring
|
|
747
|
+
}
|
|
748
|
+
$group_status.append($status)
|
|
749
|
+
}
|
|
750
|
+
return($group_status)
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function check_sync_status(group_status) {
|
|
754
|
+
$indices = $lib.set()
|
|
755
|
+
$known_count = (0)
|
|
756
|
+
for $status in $group_status {
|
|
757
|
+
$indices.add($status.nexs_indx)
|
|
758
|
+
$known_count = ($known_count + (1))
|
|
759
|
+
}
|
|
760
|
+
if ($lib.len($indices) = 1) {
|
|
761
|
+
if ($known_count = $lib.len($group_status)) {
|
|
762
|
+
return(true)
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function output_status(vname, group_status, printer) {
|
|
768
|
+
$lib.print($printer.header())
|
|
769
|
+
$lib.print($vname)
|
|
770
|
+
for $status in $group_status {
|
|
771
|
+
if ($status.nexs_indx = 0) {
|
|
772
|
+
$status.nexs_indx = '<unknown>'
|
|
773
|
+
}
|
|
774
|
+
$row = (
|
|
775
|
+
$status.name,
|
|
776
|
+
$status.role,
|
|
777
|
+
$status.online,
|
|
778
|
+
$status.ready,
|
|
779
|
+
$status.host,
|
|
780
|
+
$status.port,
|
|
781
|
+
$status.version,
|
|
782
|
+
$status.nexs_indx
|
|
783
|
+
)
|
|
784
|
+
$lib.print($printer.row($row))
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
$virtual_services = ({})
|
|
789
|
+
$member_servers = ({})
|
|
790
|
+
|
|
791
|
+
for $svc in $lib.aha.list() {
|
|
792
|
+
$name = $svc.name
|
|
793
|
+
$svcinfo = $svc.svcinfo
|
|
794
|
+
$urlinfo = $svcinfo.urlinfo
|
|
795
|
+
$hostname = $urlinfo.hostname
|
|
796
|
+
|
|
797
|
+
if ($name != $hostname) {
|
|
798
|
+
$virtual_services.$name = $svc
|
|
799
|
+
} else {
|
|
800
|
+
$member_servers.$name = $svc
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
$mirror_groups = ({})
|
|
805
|
+
for ($vname, $vsvc) in $virtual_services {
|
|
806
|
+
$vsvc_info = $vsvc.svcinfo
|
|
807
|
+
$vsvc_iden = $vsvc_info.iden
|
|
808
|
+
$vsvc_leader = $vsvc_info.leader
|
|
809
|
+
$vsvc_hostname = $vsvc_info.urlinfo.hostname
|
|
810
|
+
|
|
811
|
+
if (not $vsvc_iden or not $vsvc_hostname or not $vsvc_leader) {
|
|
812
|
+
continue
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
$primary_member = $member_servers.$vsvc_hostname
|
|
816
|
+
if (not $primary_member) {
|
|
817
|
+
continue
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
$members = ([$primary_member])
|
|
821
|
+
for ($mname, $msvc) in $member_servers {
|
|
822
|
+
if ($mname != $vsvc_hostname) {
|
|
823
|
+
$msvc_info = $msvc.svcinfo
|
|
824
|
+
if ($msvc_info.iden = $vsvc_iden and $msvc_info.leader = $vsvc_leader) {
|
|
825
|
+
$members.append($msvc)
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
if ($lib.len($members) > 1) {
|
|
831
|
+
$mirror_groups.$vname = $members
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
for ($vname, $members) in $mirror_groups {
|
|
836
|
+
$cell_infos = $get_cell_infos($vname, $timeout)
|
|
837
|
+
$group_status = $build_status_list($members, $cell_infos)
|
|
838
|
+
$lib.print('Service Mirror Groups:')
|
|
839
|
+
$output_status($vname, $group_status, $printer)
|
|
840
|
+
|
|
841
|
+
if $check_sync_status($group_status) {
|
|
842
|
+
$lib.print('Group Status: In Sync')
|
|
843
|
+
} else {
|
|
844
|
+
$lib.print(`Group Status: Out of Sync`)
|
|
845
|
+
if $wait {
|
|
846
|
+
$leader_nexs = (0)
|
|
847
|
+
for $status in $group_status {
|
|
848
|
+
if (($status.role = 'leader') and ($status.nexs_indx > 0)) {
|
|
849
|
+
$leader_nexs = $status.nexs_indx
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
if ($leader_nexs > 0) {
|
|
853
|
+
while (true) {
|
|
854
|
+
$responses = ()
|
|
855
|
+
$todo = $lib.utils.todo(waitNexsOffs, ($leader_nexs - 1), timeout=$timeout)
|
|
856
|
+
for $info in $lib.aha.callPeerApi($vname, $todo, timeout=$timeout) {
|
|
857
|
+
$svcname = $info.0
|
|
858
|
+
($ok, $info) = $info.1
|
|
859
|
+
if ($ok and $info) {
|
|
860
|
+
$responses.append(($svcname, $info))
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if ($lib.len($responses) = $lib.len($members)) {
|
|
865
|
+
$cell_infos = $get_cell_infos($vname, $timeout)
|
|
866
|
+
$group_status = $build_status_list($members, $cell_infos)
|
|
867
|
+
|
|
868
|
+
$lib.print('')
|
|
869
|
+
$lib.print('Updated status:')
|
|
870
|
+
$output_status($vname, $group_status, $printer)
|
|
871
|
+
|
|
872
|
+
if $check_sync_status($group_status) {
|
|
873
|
+
$lib.print('Group Status: In Sync')
|
|
874
|
+
break
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
$lib.print('')
|
|
882
|
+
}
|
|
883
|
+
'''
|
|
884
|
+
},
|
|
535
885
|
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import synapse.lib.stormtypes as s_stormtypes
|
|
2
|
+
|
|
3
|
+
@s_stormtypes.registry.registerLib
|
|
4
|
+
class LibUtils(s_stormtypes.Lib):
|
|
5
|
+
'''
|
|
6
|
+
A Storm library for working with utility functions.
|
|
7
|
+
'''
|
|
8
|
+
_storm_locals = (
|
|
9
|
+
{'name': 'todo',
|
|
10
|
+
'desc': '''
|
|
11
|
+
Create a todo tuple of (name, args, kwargs).
|
|
12
|
+
''',
|
|
13
|
+
'type': {'type': 'function', '_funcname': '_todo',
|
|
14
|
+
'args': (
|
|
15
|
+
{'name': '_todoname', 'type': 'str',
|
|
16
|
+
'desc': 'The todo name.'},
|
|
17
|
+
{'name': '*args', 'type': 'any',
|
|
18
|
+
'desc': 'Positional arguments for the todo.'},
|
|
19
|
+
{'name': '**kwargs', 'type': 'any',
|
|
20
|
+
'desc': 'Keyword arguments for the todo.'},
|
|
21
|
+
),
|
|
22
|
+
'returns': {'type': 'list', 'desc': 'A todo tuple of (name, args, kwargs).'},
|
|
23
|
+
}},
|
|
24
|
+
)
|
|
25
|
+
_storm_lib_path = ('utils',)
|
|
26
|
+
|
|
27
|
+
def getObjLocals(self):
|
|
28
|
+
return {
|
|
29
|
+
'todo': self._todo,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
33
|
+
async def _todo(self, _todoname, *args, **kwargs):
|
|
34
|
+
_todoname = await s_stormtypes.tostr(_todoname)
|
|
35
|
+
args = await s_stormtypes.toprim(args)
|
|
36
|
+
kwargs = await s_stormtypes.toprim(kwargs)
|
|
37
|
+
return (_todoname, args, kwargs)
|
synapse/lib/stormtypes.py
CHANGED
|
@@ -2381,6 +2381,50 @@ class LibAxon(Lib):
|
|
|
2381
2381
|
{'name': 'sha256', 'type': 'str', 'desc': 'The sha256 value to calculate hashes for.', },
|
|
2382
2382
|
),
|
|
2383
2383
|
'returns': {'type': 'dict', 'desc': 'A dictionary of additional hashes.', }}},
|
|
2384
|
+
|
|
2385
|
+
{'name': 'read', 'desc': '''
|
|
2386
|
+
Read bytes from a file stored in the Axon by its SHA256 hash.
|
|
2387
|
+
|
|
2388
|
+
Examples:
|
|
2389
|
+
Read 100 bytes starting at offset 0::
|
|
2390
|
+
|
|
2391
|
+
$byts = $lib.axon.read($sha256, size=100)
|
|
2392
|
+
|
|
2393
|
+
Read 50 bytes starting at offset 200::
|
|
2394
|
+
|
|
2395
|
+
$byts = $lib.axon.read($sha256, offs=200, size=50)
|
|
2396
|
+
''',
|
|
2397
|
+
'type': {'type': 'function', '_funcname': 'read',
|
|
2398
|
+
'args': (
|
|
2399
|
+
{'name': 'sha256', 'type': 'str', 'desc': 'The SHA256 hash of the file to read.'},
|
|
2400
|
+
{'name': 'offs', 'type': 'int', 'default': 0,
|
|
2401
|
+
'desc': 'The offset to start reading from.'},
|
|
2402
|
+
{'name': 'size', 'type': 'int', 'default': s_const.mebibyte,
|
|
2403
|
+
'desc': 'The number of bytes to read. Max is 1 MiB.'},
|
|
2404
|
+
),
|
|
2405
|
+
'returns': {'type': 'bytes', 'desc': 'The requested bytes from the file.'}}},
|
|
2406
|
+
|
|
2407
|
+
{'name': 'unpack', 'desc': '''
|
|
2408
|
+
Unpack bytes from a file stored in the Axon into a struct using the specified format.
|
|
2409
|
+
|
|
2410
|
+
Examples:
|
|
2411
|
+
Unpack two 32-bit integers from the start of a file::
|
|
2412
|
+
|
|
2413
|
+
$nums = $lib.axon.unpack($sha256, '<II')
|
|
2414
|
+
|
|
2415
|
+
Unpack a 64-bit float starting at offset 100::
|
|
2416
|
+
|
|
2417
|
+
$float = $lib.axon.unpack($sha256, '<d', offs=100)
|
|
2418
|
+
''',
|
|
2419
|
+
'type': {'type': 'function', '_funcname': 'unpack',
|
|
2420
|
+
'args': (
|
|
2421
|
+
{'name': 'sha256', 'type': 'str', 'desc': 'The SHA256 hash of the file to read.'},
|
|
2422
|
+
{'name': 'fmt', 'type': 'str', 'desc': 'The struct format string.'},
|
|
2423
|
+
{'name': 'offs', 'type': 'int', 'default': 0,
|
|
2424
|
+
'desc': 'The offset to start reading from.'},
|
|
2425
|
+
),
|
|
2426
|
+
'returns': {'type': 'list', 'desc': 'The unpacked values as a tuple.'}}},
|
|
2427
|
+
|
|
2384
2428
|
{'name': 'upload', 'desc': '''
|
|
2385
2429
|
Upload a stream of bytes to the Axon as a file.
|
|
2386
2430
|
|
|
@@ -2426,6 +2470,8 @@ class LibAxon(Lib):
|
|
|
2426
2470
|
'size': self.size,
|
|
2427
2471
|
'upload': self.upload,
|
|
2428
2472
|
'hashset': self.hashset,
|
|
2473
|
+
'read': self.read,
|
|
2474
|
+
'unpack': self.unpack,
|
|
2429
2475
|
}
|
|
2430
2476
|
|
|
2431
2477
|
@stormfunc(readonly=True)
|
|
@@ -2712,6 +2758,48 @@ class LibAxon(Lib):
|
|
|
2712
2758
|
await self.runt.snap.core.getAxon()
|
|
2713
2759
|
return await self.runt.snap.core.axon.hashset(s_common.uhex(sha256))
|
|
2714
2760
|
|
|
2761
|
+
@stormfunc(readonly=True)
|
|
2762
|
+
async def read(self, sha256, offs=0, size=s_const.mebibyte):
|
|
2763
|
+
'''
|
|
2764
|
+
Read bytes from a file in the Axon.
|
|
2765
|
+
'''
|
|
2766
|
+
sha256 = await tostr(sha256)
|
|
2767
|
+
size = await toint(size)
|
|
2768
|
+
offs = await toint(offs)
|
|
2769
|
+
|
|
2770
|
+
if size > s_const.mebibyte:
|
|
2771
|
+
mesg = f'Size must be between 1 and {s_const.mebibyte} bytes'
|
|
2772
|
+
raise s_exc.BadArg(mesg=mesg)
|
|
2773
|
+
|
|
2774
|
+
if not self.runt.allowed(('axon', 'get')):
|
|
2775
|
+
self.runt.confirm(('storm', 'lib', 'axon', 'get'))
|
|
2776
|
+
|
|
2777
|
+
await self.runt.snap.core.getAxon()
|
|
2778
|
+
|
|
2779
|
+
byts = b''
|
|
2780
|
+
async for chunk in self.runt.snap.core.axon.get(s_common.uhex(sha256), offs=offs, size=size):
|
|
2781
|
+
byts += chunk
|
|
2782
|
+
return byts
|
|
2783
|
+
|
|
2784
|
+
@stormfunc(readonly=True)
|
|
2785
|
+
async def unpack(self, sha256, fmt, offs=0):
|
|
2786
|
+
'''
|
|
2787
|
+
Unpack bytes from a file in the Axon using struct.
|
|
2788
|
+
'''
|
|
2789
|
+
if self.runt.snap.core.axoninfo.get('features', {}).get('unpack', 0) < 1:
|
|
2790
|
+
mesg = 'The connected Axon does not support the the unpack API. Please update your Axon.'
|
|
2791
|
+
raise s_exc.FeatureNotSupported(mesg=mesg)
|
|
2792
|
+
|
|
2793
|
+
sha256 = await tostr(sha256)
|
|
2794
|
+
fmt = await tostr(fmt)
|
|
2795
|
+
offs = await toint(offs)
|
|
2796
|
+
|
|
2797
|
+
if not self.runt.allowed(('axon', 'get')):
|
|
2798
|
+
self.runt.confirm(('storm', 'lib', 'axon', 'get'))
|
|
2799
|
+
|
|
2800
|
+
await self.runt.snap.core.getAxon()
|
|
2801
|
+
return await self.runt.snap.core.axon.unpack(s_common.uhex(sha256), fmt, offs)
|
|
2802
|
+
|
|
2715
2803
|
@registry.registerLib
|
|
2716
2804
|
class LibBytes(Lib):
|
|
2717
2805
|
'''
|
|
@@ -6999,6 +7087,22 @@ class Layer(Prim):
|
|
|
6999
7087
|
'returns': {'name': 'Yields', 'type': 'node',
|
|
7000
7088
|
'desc': 'Yields nodes.', }}},
|
|
7001
7089
|
|
|
7090
|
+
{'name': 'liftByNodeData', 'desc': '''
|
|
7091
|
+
Lift and yield nodes with the given node data key set within the layer.
|
|
7092
|
+
|
|
7093
|
+
Example:
|
|
7094
|
+
Yield all nodes with the data key zootsuit set in the top layer::
|
|
7095
|
+
|
|
7096
|
+
yield $lib.layer.get().liftByNodeData(zootsuit)
|
|
7097
|
+
|
|
7098
|
+
''',
|
|
7099
|
+
'type': {'type': 'function', '_funcname': 'liftByNodeData',
|
|
7100
|
+
'args': (
|
|
7101
|
+
{'name': 'name', 'type': 'str', 'desc': 'The node data name to lift by.'},
|
|
7102
|
+
),
|
|
7103
|
+
'returns': {'name': 'Yields', 'type': 'node',
|
|
7104
|
+
'desc': 'Yields nodes.', }}},
|
|
7105
|
+
|
|
7002
7106
|
{'name': 'getEdges', 'desc': '''
|
|
7003
7107
|
Yield (n1iden, verb, n2iden) tuples for any light edges in the layer.
|
|
7004
7108
|
|
|
@@ -7110,6 +7214,7 @@ class Layer(Prim):
|
|
|
7110
7214
|
'getEdges': self.getEdges,
|
|
7111
7215
|
'liftByTag': self.liftByTag,
|
|
7112
7216
|
'liftByProp': self.liftByProp,
|
|
7217
|
+
'liftByNodeData': self.liftByNodeData,
|
|
7113
7218
|
'getTagCount': self._methGetTagCount,
|
|
7114
7219
|
'getPropCount': self._methGetPropCount,
|
|
7115
7220
|
'getPropValues': self._methGetPropValues,
|
|
@@ -7177,6 +7282,19 @@ class Layer(Prim):
|
|
|
7177
7282
|
async for _, buid, sode in layr.liftByPropValu(liftform, liftprop, cmprvals):
|
|
7178
7283
|
yield await self.runt.snap._joinStorNode(buid, {iden: sode})
|
|
7179
7284
|
|
|
7285
|
+
@stormfunc(readonly=True)
|
|
7286
|
+
async def liftByNodeData(self, name):
|
|
7287
|
+
|
|
7288
|
+
name = await tostr(name)
|
|
7289
|
+
|
|
7290
|
+
iden = self.valu.get('iden')
|
|
7291
|
+
layr = self.runt.snap.core.getLayer(iden)
|
|
7292
|
+
|
|
7293
|
+
await self.runt.reqUserCanReadLayer(iden)
|
|
7294
|
+
|
|
7295
|
+
async for _, buid, sode in layr.liftByDataName(name):
|
|
7296
|
+
yield await self.runt.snap._joinStorNode(buid, {iden: sode})
|
|
7297
|
+
|
|
7180
7298
|
@stormfunc(readonly=True)
|
|
7181
7299
|
async def getMirrorStatus(self):
|
|
7182
7300
|
iden = self.valu.get('iden')
|
synapse/lib/version.py
CHANGED
|
@@ -223,6 +223,6 @@ def reqVersion(valu, reqver,
|
|
|
223
223
|
##############################################################################
|
|
224
224
|
# The following are touched during the release process by bumpversion.
|
|
225
225
|
# Do not modify these directly.
|
|
226
|
-
version = (2,
|
|
226
|
+
version = (2, 196, 0)
|
|
227
227
|
verstring = '.'.join([str(x) for x in version])
|
|
228
|
-
commit = '
|
|
228
|
+
commit = '8182360d2ebf8e8bdd00cb72f03812061c819cc2'
|
synapse/models/base.py
CHANGED
|
@@ -193,6 +193,9 @@ class BaseModule(s_module.CoreModule):
|
|
|
193
193
|
('url', ('inet:url', {}), {
|
|
194
194
|
'doc': 'A URL which documents the meta source.'}),
|
|
195
195
|
|
|
196
|
+
('ingest:cursor', ('str', {}), {
|
|
197
|
+
'doc': 'Used by ingest logic to capture the current ingest cursor within a feed.'}),
|
|
198
|
+
|
|
196
199
|
('ingest:latest', ('time', {}), {
|
|
197
200
|
'doc': 'Used by ingest logic to capture the last time a feed ingest ran.'}),
|
|
198
201
|
|