synapse 2.195.1__py311-none-any.whl → 2.197.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 +13 -8
- synapse/cryotank.py +2 -2
- synapse/daemon.py +1 -0
- synapse/lib/aha.py +159 -4
- synapse/lib/cell.py +133 -8
- synapse/lib/config.py +3 -3
- synapse/lib/jsonstor.py +2 -1
- synapse/lib/modelrev.py +5 -1
- synapse/lib/multislabseqn.py +2 -2
- synapse/lib/nexus.py +4 -1
- synapse/lib/reflect.py +4 -5
- synapse/lib/schemas.py +478 -1
- synapse/lib/snap.py +14 -7
- synapse/lib/storm.py +12 -394
- synapse/lib/stormlib/aha.py +351 -1
- synapse/lib/stormlib/graph.py +0 -61
- synapse/lib/stormlib/index.py +52 -0
- synapse/lib/stormlib/utils.py +37 -0
- synapse/lib/stormtypes.py +121 -1
- synapse/lib/task.py +13 -2
- synapse/lib/urlhelp.py +1 -1
- synapse/lib/version.py +2 -2
- synapse/models/base.py +3 -0
- synapse/models/doc.py +62 -0
- synapse/models/infotech.py +55 -16
- synapse/models/orgs.py +20 -14
- 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 +15 -0
- synapse/tests/test_lib_aha.py +201 -0
- synapse/tests/test_lib_boss.py +15 -6
- synapse/tests/test_lib_cell.py +104 -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_index.py +39 -0
- synapse/tests/test_lib_stormlib_utils.py +14 -0
- synapse/tests/test_lib_stormtypes.py +90 -3
- synapse/tests/test_lib_task.py +31 -13
- synapse/tests/test_model_base.py +2 -0
- synapse/tests/test_model_doc.py +38 -0
- synapse/tests/test_model_infotech.py +28 -1
- synapse/tests/test_model_orgs.py +9 -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/tools/genpkg.py +2 -2
- {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/METADATA +1 -1
- {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/RECORD +60 -55
- {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/LICENSE +0 -0
- {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/WHEEL +0 -0
- {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/top_level.txt +0 -0
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
|
)
|
synapse/lib/stormlib/graph.py
CHANGED
|
@@ -5,67 +5,6 @@ import synapse.lib.msgpack as s_msgpack
|
|
|
5
5
|
import synapse.lib.schemas as s_schemas
|
|
6
6
|
import synapse.lib.stormtypes as s_stormtypes
|
|
7
7
|
|
|
8
|
-
gdefSchema = {
|
|
9
|
-
'type': 'object',
|
|
10
|
-
'properties': {
|
|
11
|
-
'iden': {'type': 'string', 'pattern': s_config.re_iden},
|
|
12
|
-
'name': {'type': 'string', 'minLength': 1},
|
|
13
|
-
'desc': {'type': 'string', 'default': ''},
|
|
14
|
-
'scope': {'type': 'string', 'enum': ['user', 'power-up']},
|
|
15
|
-
'creator': {'type': 'string', 'pattern': s_config.re_iden},
|
|
16
|
-
'power-up': {'type': 'string', 'minLength': 1},
|
|
17
|
-
'maxsize': {'type': 'number', 'minimum': 0},
|
|
18
|
-
'existing': {'type': 'array', 'items': {'type': 'string'}},
|
|
19
|
-
'created': {'type': 'number'},
|
|
20
|
-
'updated': {'type': 'number'},
|
|
21
|
-
'refs': {'type': 'boolean', 'default': False},
|
|
22
|
-
'edges': {'type': 'boolean', 'default': True},
|
|
23
|
-
'edgelimit': {'type': 'number', 'default': 3000},
|
|
24
|
-
'degrees': {'type': ['integer', 'null'], 'minimum': 0},
|
|
25
|
-
'filterinput': {'type': 'boolean', 'default': True},
|
|
26
|
-
'yieldfiltered': {'type': 'boolean', 'default': False},
|
|
27
|
-
'filters': {
|
|
28
|
-
'type': ['array', 'null'],
|
|
29
|
-
'items': {'type': 'string'}
|
|
30
|
-
},
|
|
31
|
-
'pivots': {
|
|
32
|
-
'type': ['array', 'null'],
|
|
33
|
-
'items': {'type': 'string'}
|
|
34
|
-
},
|
|
35
|
-
'forms': {
|
|
36
|
-
'type': 'object',
|
|
37
|
-
'patternProperties': {
|
|
38
|
-
'^.*$': {
|
|
39
|
-
'type': 'object',
|
|
40
|
-
'properties': {
|
|
41
|
-
'filters': {
|
|
42
|
-
'type': ['array', 'null'],
|
|
43
|
-
'items': {'type': 'string'}
|
|
44
|
-
},
|
|
45
|
-
'pivots': {
|
|
46
|
-
'type': ['array', 'null'],
|
|
47
|
-
'items': {'type': 'string'}
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
'additionalProperties': False,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
'permissions': s_msgpack.deepcopy(s_schemas.easyPermSchema)
|
|
55
|
-
},
|
|
56
|
-
'additionalProperties': False,
|
|
57
|
-
'required': ['iden', 'name', 'scope'],
|
|
58
|
-
'allOf': [
|
|
59
|
-
{
|
|
60
|
-
'if': {'properties': {'scope': {'const': 'power-up'}}},
|
|
61
|
-
'then': {'required': ['power-up']},
|
|
62
|
-
'else': {'required': ['creator']},
|
|
63
|
-
}
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
reqValidGdef = s_config.getJsValidator(gdefSchema)
|
|
68
|
-
|
|
69
8
|
USER_EDITABLE = {
|
|
70
9
|
'desc',
|
|
71
10
|
'name',
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import synapse.lib.stormtypes as s_stormtypes
|
|
2
|
+
|
|
3
|
+
stormcmds = (
|
|
4
|
+
{
|
|
5
|
+
'name': 'index.count.prop',
|
|
6
|
+
'descr': '''
|
|
7
|
+
Display the number of properties or property values in the view.
|
|
8
|
+
|
|
9
|
+
Examples:
|
|
10
|
+
|
|
11
|
+
// Display the number of file:path:ext properties in the view.
|
|
12
|
+
index.count.prop file:path:ext
|
|
13
|
+
|
|
14
|
+
// Display the number of file:path:ext properties with the value
|
|
15
|
+
// "exe" in the view.
|
|
16
|
+
index.count.prop file:path:ext --value exe
|
|
17
|
+
|
|
18
|
+
''',
|
|
19
|
+
'cmdargs': (
|
|
20
|
+
('prop', {'help': 'The name of the form or property to count.'}),
|
|
21
|
+
('--value', {'help': 'The specific value to count instances of.',
|
|
22
|
+
'default': s_stormtypes.undef}),
|
|
23
|
+
),
|
|
24
|
+
'storm': '''
|
|
25
|
+
|
|
26
|
+
$conf = (
|
|
27
|
+
{"columns": [
|
|
28
|
+
{"name": "Count", "width": 12},
|
|
29
|
+
{"name": "Layer Iden", "width": 32},
|
|
30
|
+
{"name": "Layer Name"},
|
|
31
|
+
],
|
|
32
|
+
"separators": {
|
|
33
|
+
'data:row': ''
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
$printer = $lib.tabular.printer($conf)
|
|
37
|
+
|
|
38
|
+
$lib.print($printer.header())
|
|
39
|
+
|
|
40
|
+
$total = (0)
|
|
41
|
+
for $layer in $lib.view.get().layers {
|
|
42
|
+
|
|
43
|
+
$count = $layer.getPropCount($cmdopts.prop, valu=$cmdopts.value)
|
|
44
|
+
|
|
45
|
+
$total = ($total + $count)
|
|
46
|
+
|
|
47
|
+
$lib.print($printer.row(($count, $layer.iden, $layer.name)))
|
|
48
|
+
}
|
|
49
|
+
$lib.print(`Total: {$total}`)
|
|
50
|
+
''',
|
|
51
|
+
},
|
|
52
|
+
)
|
|
@@ -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)
|