synapse 2.176.0__py311-none-any.whl → 2.178.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 +24 -9
- synapse/cortex.py +337 -172
- synapse/cryotank.py +46 -37
- synapse/datamodel.py +17 -4
- synapse/exc.py +19 -0
- synapse/lib/agenda.py +7 -13
- synapse/lib/aha.py +361 -88
- synapse/lib/auth.py +1520 -0
- synapse/lib/base.py +27 -9
- synapse/lib/cell.py +422 -163
- synapse/lib/config.py +15 -11
- synapse/lib/coro.py +13 -0
- synapse/lib/grammar.py +5 -0
- synapse/lib/hive.py +24 -3
- synapse/lib/hiveauth.py +6 -32
- synapse/lib/layer.py +7 -9
- synapse/lib/link.py +22 -18
- synapse/lib/lmdbslab.py +152 -3
- synapse/lib/modelrev.py +1 -1
- synapse/lib/nexus.py +24 -12
- synapse/lib/schemas.py +136 -0
- synapse/lib/storm.py +61 -29
- synapse/lib/stormlib/aha.py +1 -1
- synapse/lib/stormlib/auth.py +185 -10
- synapse/lib/stormlib/cortex.py +16 -5
- synapse/lib/stormlib/gen.py +80 -0
- synapse/lib/stormlib/imap.py +6 -2
- synapse/lib/stormlib/model.py +55 -0
- synapse/lib/stormlib/modelext.py +60 -0
- synapse/lib/stormlib/smtp.py +12 -2
- synapse/lib/stormlib/tabular.py +212 -0
- synapse/lib/stormtypes.py +14 -1
- synapse/lib/trigger.py +1 -1
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +55 -28
- synapse/models/base.py +7 -0
- synapse/models/biz.py +4 -0
- synapse/models/files.py +8 -1
- synapse/models/inet.py +8 -0
- synapse/telepath.py +32 -17
- synapse/tests/files/aha/certs/cas/synapse.crt +28 -0
- synapse/tests/files/aha/certs/cas/synapse.key +51 -0
- synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.crt +30 -0
- synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.key +51 -0
- synapse/tests/files/aha/certs/users/root@synapse.crt +29 -0
- synapse/tests/files/aha/certs/users/root@synapse.key +51 -0
- synapse/tests/files/changelog/model_2.176.0_16ee721a6b7221344eaf946c3ab4602dda546b1a.yaml.gz +0 -0
- synapse/tests/files/changelog/model_2.176.0_2a25c58bbd344716cd7cbc3f4304d8925b0f4ef2.yaml.gz +0 -0
- synapse/tests/files/rstorm/testsvc.py +1 -1
- synapse/tests/test_axon.py +8 -5
- synapse/tests/test_cortex.py +149 -141
- synapse/tests/test_cryotank.py +4 -4
- synapse/tests/test_datamodel.py +7 -0
- synapse/tests/test_lib_agenda.py +10 -3
- synapse/tests/test_lib_aha.py +336 -490
- synapse/tests/{test_lib_hiveauth.py → test_lib_auth.py} +314 -11
- synapse/tests/test_lib_base.py +20 -0
- synapse/tests/test_lib_cell.py +210 -30
- synapse/tests/test_lib_config.py +4 -3
- synapse/tests/test_lib_httpapi.py +18 -14
- synapse/tests/test_lib_layer.py +33 -33
- synapse/tests/test_lib_link.py +42 -1
- synapse/tests/test_lib_lmdbslab.py +68 -0
- synapse/tests/test_lib_nexus.py +12 -4
- synapse/tests/test_lib_node.py +0 -7
- synapse/tests/test_lib_storm.py +45 -0
- synapse/tests/test_lib_stormlib_aha.py +35 -36
- synapse/tests/test_lib_stormlib_auth.py +21 -0
- synapse/tests/test_lib_stormlib_cell.py +4 -15
- synapse/tests/test_lib_stormlib_cortex.py +12 -12
- synapse/tests/test_lib_stormlib_gen.py +99 -0
- synapse/tests/test_lib_stormlib_imap.py +14 -3
- synapse/tests/test_lib_stormlib_model.py +108 -0
- synapse/tests/test_lib_stormlib_modelext.py +64 -0
- synapse/tests/test_lib_stormlib_smtp.py +51 -0
- synapse/tests/test_lib_stormlib_tabular.py +226 -0
- synapse/tests/test_lib_stormsvc.py +4 -1
- synapse/tests/test_lib_stormtypes.py +10 -0
- synapse/tests/test_model_base.py +3 -0
- synapse/tests/test_model_biz.py +3 -0
- synapse/tests/test_model_files.py +12 -2
- synapse/tests/test_model_inet.py +24 -0
- synapse/tests/test_tools_aha.py +78 -101
- synapse/tests/test_tools_changelog.py +196 -0
- synapse/tests/test_tools_healthcheck.py +4 -3
- synapse/tests/utils.py +87 -121
- synapse/tools/aha/clone.py +50 -0
- synapse/tools/aha/enroll.py +2 -1
- synapse/tools/backup.py +2 -2
- synapse/tools/changelog.py +776 -15
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/METADATA +48 -48
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/RECORD +95 -82
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/WHEEL +1 -1
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/LICENSE +0 -0
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import synapse.tests.utils as s_test_utils
|
|
2
|
+
|
|
3
|
+
import synapse.tools.changelog as s_t_changelog
|
|
4
|
+
|
|
5
|
+
class ChangelogToolTest(s_test_utils.SynTest):
|
|
6
|
+
|
|
7
|
+
async def test_model_diff(self):
|
|
8
|
+
outp = self.getTestOutp()
|
|
9
|
+
old_fp = self.getTestFilePath('changelog', 'model_2.176.0_16ee721a6b7221344eaf946c3ab4602dda546b1a.yaml.gz')
|
|
10
|
+
new_fp = self.getTestFilePath('changelog', 'model_2.176.0_2a25c58bbd344716cd7cbc3f4304d8925b0f4ef2.yaml.gz')
|
|
11
|
+
oldmodel = s_t_changelog._getModelFile(old_fp)
|
|
12
|
+
newmodel = s_t_changelog._getModelFile(new_fp)
|
|
13
|
+
|
|
14
|
+
differ = s_t_changelog.ModelDiffer(newmodel.get('model'), oldmodel.get('model'))
|
|
15
|
+
|
|
16
|
+
self.eq(differ.cur_type2iface['it:host'], ['inet:service:object', 'inet:service:base'])
|
|
17
|
+
self.eq(differ.cur_type2iface['mat:type'], ['meta:taxonomy'])
|
|
18
|
+
self.eq(differ.cur_iface_to_allifaces['it:host:activity'], ['it:host:activity'])
|
|
19
|
+
self.eq(differ.cur_iface_to_allifaces['file:mime:msoffice'], ['file:mime:msoffice', 'file:mime:meta'])
|
|
20
|
+
changes = differ.diffModl(outp)
|
|
21
|
+
|
|
22
|
+
self.len(4, changes.get('edges').get('new_edges'))
|
|
23
|
+
|
|
24
|
+
form_chng = changes.get('forms')
|
|
25
|
+
self.isin('it:beeper:thingy', form_chng.get('new_forms'))
|
|
26
|
+
self.notin('it:beeper:name', form_chng.get('new_forms'))
|
|
27
|
+
updt_frms = form_chng.get('updated_forms')
|
|
28
|
+
self.isin('new_properties', updt_frms.get('file:mime:pe:resource'))
|
|
29
|
+
self.isin('new_properties_no_interfaces', updt_frms.get('file:mime:pe:resource'))
|
|
30
|
+
self.isin('new_properties', updt_frms.get('inet:http:request'))
|
|
31
|
+
self.notin('new_properties_no_interfaces', updt_frms.get('inet:http:request'))
|
|
32
|
+
self.isin('updated_properties', updt_frms.get('file:mime:macho:section'))
|
|
33
|
+
self.isin('deprecated_properties', updt_frms.get('file:mime:lnk'))
|
|
34
|
+
self.isin('deprecated_properties_no_interfaces', updt_frms.get('file:mime:lnk'))
|
|
35
|
+
self.isin('deprecated_properties', updt_frms.get('inet:http:request'))
|
|
36
|
+
self.notin('deprecated_properties_no_interfaces', updt_frms.get('inet:http:request'))
|
|
37
|
+
self.isin('new_properties', updt_frms.get('file:mime:lnk'))
|
|
38
|
+
self.isin('new_properties_no_interfaces', updt_frms.get('file:mime:lnk'))
|
|
39
|
+
self.isin('updated_properties', updt_frms.get('file:mime:lnk'))
|
|
40
|
+
self.isin('updated_properties_no_interfaces', updt_frms.get('file:mime:lnk'))
|
|
41
|
+
self.isin('updated_properties', updt_frms.get('inet:service:access'))
|
|
42
|
+
self.notin('updated_properties_no_interfaces', updt_frms.get('inet:service:access'))
|
|
43
|
+
|
|
44
|
+
self.isin('it:host:beeper', changes.get('interfaces').get('new_interfaces'))
|
|
45
|
+
updt_iface = changes.get('interfaces').get('updated_interfaces')
|
|
46
|
+
self.isin('deprecated_properties', updt_iface.get('it:host:activity'))
|
|
47
|
+
self.isin('new_properties', updt_iface.get('it:host:activity'))
|
|
48
|
+
self.isin('updated_properties', updt_iface.get('inet:service:base'))
|
|
49
|
+
|
|
50
|
+
self.eq(changes.get('tagprops'), {})
|
|
51
|
+
|
|
52
|
+
self.isin('it:reveng:function', changes.get('types').get('deprecated_types'))
|
|
53
|
+
self.isin('inet:port', changes.get('types').get('deprecated_types'))
|
|
54
|
+
self.isin('it:beeper:thingy', changes.get('types').get('new_types'))
|
|
55
|
+
self.isin('it:beeper:name', changes.get('types').get('new_types'))
|
|
56
|
+
uptd_types = changes.get('types').get('updated_types')
|
|
57
|
+
self.isin('updated_opts', uptd_types.get('it:query'))
|
|
58
|
+
self.isin('updated_interfaces', uptd_types.get('it:reveng:impfunc'))
|
|
59
|
+
|
|
60
|
+
rst = s_t_changelog._gen_model_rst('v2.177.0', 'userguide_model_v2_177_0',
|
|
61
|
+
changes, newmodel.get('model'), outp)
|
|
62
|
+
text = rst.getRstText()
|
|
63
|
+
self.isin('v2.177.0 Model Updates', text)
|
|
64
|
+
self.isin('''**************
|
|
65
|
+
New Interfaces
|
|
66
|
+
**************
|
|
67
|
+
|
|
68
|
+
``it:host:beeper``
|
|
69
|
+
Properties common to instances of beepers.''', text)
|
|
70
|
+
self.isin('''*********
|
|
71
|
+
New Types
|
|
72
|
+
*********
|
|
73
|
+
|
|
74
|
+
``it:beeper:name``
|
|
75
|
+
The friendly name of a beeper.
|
|
76
|
+
''', text)
|
|
77
|
+
self.isin('''*********
|
|
78
|
+
New Forms
|
|
79
|
+
*********
|
|
80
|
+
|
|
81
|
+
``it:beeper:thingy``
|
|
82
|
+
A beeper thingy.
|
|
83
|
+
''', text)
|
|
84
|
+
self.isin('''**************
|
|
85
|
+
New Properties
|
|
86
|
+
**************
|
|
87
|
+
|
|
88
|
+
``file:mime:lnk``
|
|
89
|
+
The form had the following properties added to it:
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
``driveserial``
|
|
93
|
+
The drive serial number of the volume the link target is stored on.
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
``iconindex``
|
|
97
|
+
A resource index for an icon within an icon location.
|
|
98
|
+
''', text)
|
|
99
|
+
self.isin('''``inet:http:request``
|
|
100
|
+
The form had the following property added to it:
|
|
101
|
+
|
|
102
|
+
``beep``
|
|
103
|
+
The time that the host went beep.
|
|
104
|
+
''', text)
|
|
105
|
+
# Some updates will require manual intervention to rewrite.
|
|
106
|
+
self.isin('''******************
|
|
107
|
+
Updated Interfaces
|
|
108
|
+
******************
|
|
109
|
+
|
|
110
|
+
``inet:service:base``
|
|
111
|
+
The property ``id`` has been modified from ['str', {'strip': True}] to ['str',
|
|
112
|
+
{'lower': True, 'strip': True}].
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
``it:host:activity``
|
|
116
|
+
The interface property ``time`` has been deprecated.
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
The property ``beep`` has been added to the interface.
|
|
120
|
+
''', text)
|
|
121
|
+
self.isin('''*************
|
|
122
|
+
Updated Types
|
|
123
|
+
*************
|
|
124
|
+
|
|
125
|
+
``it:query``
|
|
126
|
+
The type has been modified from {'enums': None, 'globsuffix': False, 'lower':
|
|
127
|
+
False, 'onespace': False, 'regex': None, 'replace': [], 'strip': True} to
|
|
128
|
+
{'enums': None, 'globsuffix': False, 'lower': True, 'onespace': False,
|
|
129
|
+
'regex': None, 'replace': [], 'strip': True}.
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
``it:reveng:impfunc``
|
|
133
|
+
The type interface has been modified from None to ['it:host:beeper'].
|
|
134
|
+
''', text)
|
|
135
|
+
self.isin('''******************
|
|
136
|
+
Updated Properties
|
|
137
|
+
******************
|
|
138
|
+
|
|
139
|
+
``file:mime:lnk``
|
|
140
|
+
The form had the following property updated:
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
The property ``entry:icon`` has been modified from ['file:path', {}] to
|
|
144
|
+
['time', {}].
|
|
145
|
+
''', text)
|
|
146
|
+
self.isin('''***********
|
|
147
|
+
Light Edges
|
|
148
|
+
***********
|
|
149
|
+
|
|
150
|
+
``jenkies``
|
|
151
|
+
When used with a ``it:prod:soft`` node, the edge indicates The software uses
|
|
152
|
+
the jenkies technique.
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
``loves``
|
|
156
|
+
The source node loves the target node.
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
``sneaky``
|
|
160
|
+
When used with a ``ou:technique`` target node, the edge indicates The
|
|
161
|
+
technique referred to is sneakily used.
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
``zoinks``
|
|
165
|
+
When used with a ``it:prod:soft`` and an ``ou:technique`` node, the edge
|
|
166
|
+
indicates The software uses the zoinks technique.
|
|
167
|
+
''', text)
|
|
168
|
+
self.isin('''****************
|
|
169
|
+
Deprecated Types
|
|
170
|
+
****************
|
|
171
|
+
|
|
172
|
+
The following types have been marked as deprecated:
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
* ``inet:port``
|
|
176
|
+
|
|
177
|
+
''', text)
|
|
178
|
+
self.isin('''****************
|
|
179
|
+
Deprecated Types
|
|
180
|
+
****************
|
|
181
|
+
|
|
182
|
+
The following forms have been marked as deprecated:
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
* ``it:reveng:function``
|
|
186
|
+
''', text)
|
|
187
|
+
self.isin('''*********************
|
|
188
|
+
Deprecated Properties
|
|
189
|
+
*********************
|
|
190
|
+
|
|
191
|
+
``file:mime:lnk``
|
|
192
|
+
The form had the following property deprecated:
|
|
193
|
+
|
|
194
|
+
``target:attrs``
|
|
195
|
+
The attributes of the target file according to the LNK header.
|
|
196
|
+
''', text)
|
|
@@ -65,11 +65,12 @@ class HealthcheckTest(s_t_utils.SynTest):
|
|
|
65
65
|
m = 'Synapse error encountered.'
|
|
66
66
|
self.eq(resp.get('components')[0].get('mesg'), m)
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
visi = await core.auth.addUser('visi')
|
|
69
|
+
await visi.setPasswd('secret')
|
|
70
|
+
|
|
69
71
|
logger.info('Checking without perms')
|
|
70
|
-
await root.setAdmin(False)
|
|
71
72
|
outp.clear()
|
|
72
|
-
retn = await s_t_healthcheck.main(['-c',
|
|
73
|
+
retn = await s_t_healthcheck.main(['-c', f'tcp://visi:secret@127.0.0.1:{port}/cortex', '-t', '0.2'], outp)
|
|
73
74
|
self.eq(retn, 1)
|
|
74
75
|
resp = json.loads(str(outp))
|
|
75
76
|
self.eq(resp.get('components')[0].get('name'), 'error')
|
synapse/tests/utils.py
CHANGED
|
@@ -677,7 +677,7 @@ class TstEnv:
|
|
|
677
677
|
|
|
678
678
|
class TstOutPut(s_output.OutPutStr):
|
|
679
679
|
|
|
680
|
-
def expect(self, substr, throw=True):
|
|
680
|
+
def expect(self, substr, throw=True, whitespace=True):
|
|
681
681
|
'''
|
|
682
682
|
Check if a string is present in the messages captured by the OutPutStr object.
|
|
683
683
|
|
|
@@ -689,6 +689,11 @@ class TstOutPut(s_output.OutPutStr):
|
|
|
689
689
|
bool: True if the string is present; False if the string is not present and throw is False.
|
|
690
690
|
'''
|
|
691
691
|
outs = str(self)
|
|
692
|
+
|
|
693
|
+
if not whitespace:
|
|
694
|
+
outs = ' '.join(outs.split())
|
|
695
|
+
substr = ' '.join(outs.split())
|
|
696
|
+
|
|
692
697
|
if outs.find(substr) == -1:
|
|
693
698
|
if throw:
|
|
694
699
|
mesg = 'TestOutPut.expect(%s) not in %s' % (substr, outs)
|
|
@@ -1297,34 +1302,20 @@ class SynTest(unittest.TestCase):
|
|
|
1297
1302
|
Returns:
|
|
1298
1303
|
s_cortex.Cortex: A Cortex object.
|
|
1299
1304
|
'''
|
|
1300
|
-
|
|
1301
|
-
conf = {
|
|
1302
|
-
'health:sysctl:checks': False,
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
conf = copy.deepcopy(conf)
|
|
1305
|
+
conf = self.getCellConf(conf=conf)
|
|
1306
1306
|
|
|
1307
|
-
mods = conf.get('modules')
|
|
1308
|
-
|
|
1309
|
-
if mods is None:
|
|
1310
|
-
mods = []
|
|
1311
|
-
conf['modules'] = mods
|
|
1307
|
+
mods = list(conf.get('modules', ()))
|
|
1308
|
+
conf['modules'] = mods
|
|
1312
1309
|
|
|
1313
1310
|
mods.insert(0, ('synapse.tests.utils.TestModule', {'key': 'valu'}))
|
|
1314
1311
|
|
|
1315
1312
|
with self.withNexusReplay():
|
|
1316
1313
|
|
|
1317
|
-
|
|
1314
|
+
with self.mayTestDir(dirn) as dirn:
|
|
1318
1315
|
|
|
1319
1316
|
async with await s_cortex.Cortex.anit(dirn, conf=conf) as core:
|
|
1320
1317
|
yield core
|
|
1321
1318
|
|
|
1322
|
-
return
|
|
1323
|
-
|
|
1324
|
-
with self.getTestDir() as dirn:
|
|
1325
|
-
async with await s_cortex.Cortex.anit(dirn, conf=conf) as core:
|
|
1326
|
-
yield core
|
|
1327
|
-
|
|
1328
1319
|
@contextlib.asynccontextmanager
|
|
1329
1320
|
async def getTestCoreAndProxy(self, conf=None, dirn=None):
|
|
1330
1321
|
'''
|
|
@@ -1342,11 +1333,7 @@ class SynTest(unittest.TestCase):
|
|
|
1342
1333
|
@contextlib.asynccontextmanager
|
|
1343
1334
|
async def getTestJsonStor(self, dirn=None, conf=None):
|
|
1344
1335
|
|
|
1345
|
-
|
|
1346
|
-
conf = {
|
|
1347
|
-
'health:sysctl:checks': False,
|
|
1348
|
-
}
|
|
1349
|
-
conf = copy.deepcopy(conf)
|
|
1336
|
+
conf = self.getCellConf(conf=conf)
|
|
1350
1337
|
|
|
1351
1338
|
with self.withNexusReplay():
|
|
1352
1339
|
if dirn is not None:
|
|
@@ -1367,20 +1354,10 @@ class SynTest(unittest.TestCase):
|
|
|
1367
1354
|
Returns:
|
|
1368
1355
|
s_cryotank.CryoCell: Test cryocell.
|
|
1369
1356
|
'''
|
|
1370
|
-
|
|
1371
|
-
conf = {
|
|
1372
|
-
'health:sysctl:checks': False,
|
|
1373
|
-
}
|
|
1374
|
-
conf = copy.deepcopy(conf)
|
|
1357
|
+
conf = self.getCellConf(conf=conf)
|
|
1375
1358
|
|
|
1376
1359
|
with self.withNexusReplay():
|
|
1377
|
-
|
|
1378
|
-
async with await s_cryotank.CryoCell.anit(dirn, conf=conf) as cryo:
|
|
1379
|
-
yield cryo
|
|
1380
|
-
|
|
1381
|
-
return
|
|
1382
|
-
|
|
1383
|
-
with self.getTestDir() as dirn:
|
|
1360
|
+
with self.mayTestDir(dirn) as dirn:
|
|
1384
1361
|
async with await s_cryotank.CryoCell.anit(dirn, conf=conf) as cryo:
|
|
1385
1362
|
yield cryo
|
|
1386
1363
|
|
|
@@ -1409,26 +1386,13 @@ class SynTest(unittest.TestCase):
|
|
|
1409
1386
|
s_certdir.delCertPath(certpath)
|
|
1410
1387
|
|
|
1411
1388
|
@contextlib.asynccontextmanager
|
|
1412
|
-
async def getTestCell(self, ctor, conf=None, dirn=None):
|
|
1389
|
+
async def getTestCell(self, ctor=s_cell.Cell, conf=None, dirn=None):
|
|
1413
1390
|
'''
|
|
1414
1391
|
Get a test Cell.
|
|
1415
1392
|
'''
|
|
1416
|
-
|
|
1417
|
-
conf = {
|
|
1418
|
-
'health:sysctl:checks': False,
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
conf = copy.deepcopy(conf)
|
|
1422
|
-
|
|
1393
|
+
conf = self.getCellConf(conf=conf)
|
|
1423
1394
|
with self.withNexusReplay():
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
async with await ctor.anit(dirn, conf=conf) as cell:
|
|
1427
|
-
yield cell
|
|
1428
|
-
|
|
1429
|
-
return
|
|
1430
|
-
|
|
1431
|
-
with self.getTestDir() as dirn:
|
|
1395
|
+
with self.mayTestDir(dirn) as dirn:
|
|
1432
1396
|
async with await ctor.anit(dirn, conf=conf) as cell:
|
|
1433
1397
|
yield cell
|
|
1434
1398
|
|
|
@@ -1451,62 +1415,77 @@ class SynTest(unittest.TestCase):
|
|
|
1451
1415
|
|
|
1452
1416
|
yield core, prox, testsvc
|
|
1453
1417
|
|
|
1418
|
+
@contextlib.contextmanager
|
|
1419
|
+
def mayTestDir(self, dirn: str | None) -> contextlib.AbstractContextManager[str, None, None]:
|
|
1420
|
+
'''
|
|
1421
|
+
Convenience method to make a temporary directory or use an existing one.
|
|
1422
|
+
|
|
1423
|
+
Args:
|
|
1424
|
+
dirn: Directory to use, or None.
|
|
1425
|
+
|
|
1426
|
+
Returns:
|
|
1427
|
+
The directory to use.
|
|
1428
|
+
'''
|
|
1429
|
+
if dirn is not None:
|
|
1430
|
+
yield dirn
|
|
1431
|
+
return
|
|
1432
|
+
|
|
1433
|
+
with self.getTestDir() as dirn:
|
|
1434
|
+
yield dirn
|
|
1435
|
+
|
|
1454
1436
|
@contextlib.asynccontextmanager
|
|
1455
|
-
async def getTestAha(self, conf=None, dirn=None):
|
|
1437
|
+
async def getTestAha(self, conf=None, dirn=None, ctor=None):
|
|
1456
1438
|
|
|
1457
1439
|
if conf is None:
|
|
1458
|
-
conf = {
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1440
|
+
conf = {}
|
|
1441
|
+
|
|
1442
|
+
if ctor is None:
|
|
1443
|
+
ctor = s_aha.AhaCell.anit
|
|
1444
|
+
|
|
1445
|
+
conf = s_msgpack.deepcopy(conf)
|
|
1446
|
+
|
|
1447
|
+
hasdmonlisn = 'dmon:listen' in conf
|
|
1448
|
+
hasprovlisn = 'provision:listen' in conf
|
|
1449
|
+
|
|
1450
|
+
network = conf.setdefault('aha:network', 'synapse')
|
|
1451
|
+
hostname = conf.setdefault('dns:name', '00.aha.loop.vertex.link')
|
|
1452
|
+
|
|
1453
|
+
if hostname:
|
|
1454
|
+
conf.setdefault('provision:listen', f'ssl://0.0.0.0:0?hostname={hostname}')
|
|
1455
|
+
conf.setdefault('dmon:listen', f'ssl://0.0.0.0:0?hostname={hostname}&ca={network}')
|
|
1456
|
+
|
|
1457
|
+
conf.setdefault('health:sysctl:checks', False)
|
|
1462
1458
|
|
|
1463
1459
|
with self.withNexusReplay():
|
|
1464
|
-
if dirn:
|
|
1465
|
-
async with await s_aha.AhaCell.anit(dirn, conf=conf) as aha:
|
|
1466
|
-
yield aha
|
|
1467
|
-
else:
|
|
1468
|
-
with self.getTestDir() as dirn:
|
|
1469
|
-
async with await s_aha.AhaCell.anit(dirn, conf=conf) as aha:
|
|
1470
|
-
yield aha
|
|
1471
1460
|
|
|
1472
|
-
|
|
1473
|
-
async def getTestAhaProv(self, conf=None, dirn=None):
|
|
1474
|
-
'''
|
|
1475
|
-
Get an Aha cell that is configured for provisioning on aha.loop.vertex.link.
|
|
1461
|
+
with self.mayTestDir(dirn) as dirn:
|
|
1476
1462
|
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1463
|
+
if conf.get('aha:network') == 'synapse':
|
|
1464
|
+
dstpath = os.path.join(dirn, 'certs')
|
|
1465
|
+
if not os.path.isdir(dstpath):
|
|
1466
|
+
srcpath = self.getTestFilePath('aha/certs')
|
|
1467
|
+
shutil.copytree(srcpath, os.path.join(dirn, 'certs'))
|
|
1480
1468
|
|
|
1481
|
-
|
|
1482
|
-
s_aha.AhaCell: The provisioned Aha cell.
|
|
1483
|
-
'''
|
|
1484
|
-
bconf = {
|
|
1485
|
-
'aha:name': 'aha',
|
|
1486
|
-
'aha:network': 'loop.vertex.link',
|
|
1487
|
-
'provision:listen': 'ssl://aha.loop.vertex.link:0'
|
|
1488
|
-
}
|
|
1469
|
+
async with await ctor(dirn, conf=conf) as aha:
|
|
1489
1470
|
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
for k, v in bconf.items():
|
|
1494
|
-
conf.setdefault(k, v)
|
|
1471
|
+
mods = {}
|
|
1472
|
+
if not hasdmonlisn and hostname:
|
|
1473
|
+
mods['dmon:listen'] = f'ssl://0.0.0.0:{aha.sockaddr[1]}?hostname={hostname}&ca={network}'
|
|
1495
1474
|
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
dnsname = f'{name}.{netw}'
|
|
1475
|
+
if not hasprovlisn and hostname:
|
|
1476
|
+
mods['provision:listen'] = f'ssl://0.0.0.0:{aha.provaddr[1]}?hostname={hostname}'
|
|
1499
1477
|
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
# update the config to reflect the dynamically bound port
|
|
1503
|
-
aha.conf['provision:listen'] = f'ssl://{dnsname}:{port}'
|
|
1478
|
+
if mods:
|
|
1479
|
+
aha.modCellConf(mods)
|
|
1504
1480
|
|
|
1505
|
-
|
|
1506
|
-
host, ahaport = await aha.dmon.listen(f'ssl://0.0.0.0:0?hostname={dnsname}&ca={netw}')
|
|
1507
|
-
aha.conf['aha:urls'] = (f'ssl://{dnsname}:{ahaport}',)
|
|
1481
|
+
yield aha
|
|
1508
1482
|
|
|
1509
|
-
|
|
1483
|
+
def getCellConf(self, conf=None):
|
|
1484
|
+
if conf is None:
|
|
1485
|
+
conf = {}
|
|
1486
|
+
conf = s_msgpack.deepcopy(conf)
|
|
1487
|
+
conf.setdefault('health:sysctl:checks', False)
|
|
1488
|
+
return conf
|
|
1510
1489
|
|
|
1511
1490
|
@contextlib.asynccontextmanager
|
|
1512
1491
|
async def addSvcToAha(self, aha, svcname, ctor,
|
|
@@ -1528,36 +1507,19 @@ class SynTest(unittest.TestCase):
|
|
|
1528
1507
|
The config data for the cell is pushed into dirn/cell.yaml.
|
|
1529
1508
|
The cells are created with the ``ctor.anit()`` function.
|
|
1530
1509
|
'''
|
|
1510
|
+
ahanetw = aha.conf.req('aha:network')
|
|
1511
|
+
svcfull = f'{svcname}.{ahanetw}'
|
|
1531
1512
|
onetime = await aha.addAhaSvcProv(svcname, provinfo=provinfo)
|
|
1532
1513
|
|
|
1533
|
-
|
|
1534
|
-
conf = {
|
|
1535
|
-
'health:sysctl:checks': False,
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1514
|
+
conf = self.getCellConf(conf=conf)
|
|
1538
1515
|
conf['aha:provision'] = onetime
|
|
1539
1516
|
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
n = 1 # a simple svcname like "foo"
|
|
1543
|
-
if len(svcname.split('.')) > 1:
|
|
1544
|
-
n = 2 # A replica name like 00.foo
|
|
1545
|
-
if provinfo and 'mirror' in provinfo:
|
|
1546
|
-
n = 1 # A mirror like 01.foo with mirror: foo
|
|
1547
|
-
|
|
1548
|
-
waiter = aha.waiter(n, 'aha:svcadd')
|
|
1549
|
-
|
|
1550
|
-
if dirn:
|
|
1517
|
+
waiter = aha.waiter(1, f'aha:svcadd:{svcfull}')
|
|
1518
|
+
with self.mayTestDir(dirn) as dirn:
|
|
1551
1519
|
s_common.yamlsave(conf, dirn, 'cell.yaml')
|
|
1552
1520
|
async with await ctor.anit(dirn) as svc:
|
|
1553
|
-
self.
|
|
1521
|
+
self.true(await waiter.wait(timeout=12))
|
|
1554
1522
|
yield svc
|
|
1555
|
-
else:
|
|
1556
|
-
with self.getTestDir() as dirn:
|
|
1557
|
-
s_common.yamlsave(conf, dirn, 'cell.yaml')
|
|
1558
|
-
async with await ctor.anit(dirn) as svc:
|
|
1559
|
-
self.ge(len(await waiter.wait(timeout=12)), n)
|
|
1560
|
-
yield svc
|
|
1561
1523
|
|
|
1562
1524
|
async def addSvcToCore(self, svc, core, svcname='svc'):
|
|
1563
1525
|
'''
|
|
@@ -1592,7 +1554,7 @@ class SynTest(unittest.TestCase):
|
|
|
1592
1554
|
return s_telepath.openurl(f'tcp:///{name}', **kwargs)
|
|
1593
1555
|
|
|
1594
1556
|
@contextlib.contextmanager
|
|
1595
|
-
def getTestDir(self, mirror=None, copyfrom=None, chdir=False, startdir=None):
|
|
1557
|
+
def getTestDir(self, mirror=None, copyfrom=None, chdir=False, startdir=None) -> contextlib.AbstractContextManager[str, None, None]:
|
|
1596
1558
|
'''
|
|
1597
1559
|
Get a temporary directory for test purposes.
|
|
1598
1560
|
This destroys the directory afterwards.
|
|
@@ -1785,7 +1747,7 @@ class SynTest(unittest.TestCase):
|
|
|
1785
1747
|
await stream.wait(timeout=10)
|
|
1786
1748
|
|
|
1787
1749
|
data = stream.getvalue()
|
|
1788
|
-
raw_mesgs = [m for m in data.split('
|
|
1750
|
+
raw_mesgs = [m for m in data.split('\n') if m]
|
|
1789
1751
|
msgs = [json.loads(m) for m in raw_mesgs]
|
|
1790
1752
|
# Do something with messages
|
|
1791
1753
|
|
|
@@ -2058,6 +2020,7 @@ class SynTest(unittest.TestCase):
|
|
|
2058
2020
|
Assert X is not None
|
|
2059
2021
|
'''
|
|
2060
2022
|
self.assertIsNotNone(x, msg=msg)
|
|
2023
|
+
return x
|
|
2061
2024
|
|
|
2062
2025
|
def none(self, x, msg=None):
|
|
2063
2026
|
'''
|
|
@@ -2154,7 +2117,7 @@ class SynTest(unittest.TestCase):
|
|
|
2154
2117
|
count += 1
|
|
2155
2118
|
self.eq(x, count, msg=msg)
|
|
2156
2119
|
|
|
2157
|
-
def stormIsInPrint(self, mesg, mesgs, deguid=False):
|
|
2120
|
+
def stormIsInPrint(self, mesg, mesgs, deguid=False, whitespace=True):
|
|
2158
2121
|
'''
|
|
2159
2122
|
Check if a string is present in all of the print messages from a stream of storm messages.
|
|
2160
2123
|
|
|
@@ -2166,6 +2129,9 @@ class SynTest(unittest.TestCase):
|
|
|
2166
2129
|
mesg = deguidify(mesg)
|
|
2167
2130
|
|
|
2168
2131
|
print_str = '\n'.join([m[1].get('mesg') for m in mesgs if m[0] == 'print'])
|
|
2132
|
+
if not whitespace:
|
|
2133
|
+
mesg = ' '.join(mesg.split())
|
|
2134
|
+
print_str = ' '.join(print_str.split())
|
|
2169
2135
|
|
|
2170
2136
|
if deguid:
|
|
2171
2137
|
print_str = deguidify(print_str)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import asyncio
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
import synapse.exc as s_exc
|
|
6
|
+
import synapse.telepath as s_telepath
|
|
7
|
+
|
|
8
|
+
import synapse.lib.output as s_output
|
|
9
|
+
|
|
10
|
+
descr = '''
|
|
11
|
+
Generate a new clone URL to deploy an AHA mirror.
|
|
12
|
+
|
|
13
|
+
Examples:
|
|
14
|
+
|
|
15
|
+
python -m synapse.tools.aha.clone 01.aha.loop.vertex.link
|
|
16
|
+
|
|
17
|
+
'''
|
|
18
|
+
|
|
19
|
+
async def main(argv, outp=s_output.stdout):
|
|
20
|
+
|
|
21
|
+
pars = argparse.ArgumentParser(prog='synapse.tools.aha.clone', description=descr)
|
|
22
|
+
pars.add_argument('dnsname', help='The DNS name of the new AHA server.')
|
|
23
|
+
pars.add_argument('--port', type=int, default=27492, help='The port that the new AHA server should listen on.')
|
|
24
|
+
pars.add_argument('--url', default='cell:///vertex/storage', help='The telepath URL to connect to the AHA service.')
|
|
25
|
+
pars.add_argument('--only-url', help='Only output the URL upon successful execution',
|
|
26
|
+
action='store_true', default=False)
|
|
27
|
+
opts = pars.parse_args(argv)
|
|
28
|
+
|
|
29
|
+
async with s_telepath.withTeleEnv():
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
async with await s_telepath.openurl(opts.url) as aha:
|
|
33
|
+
curl = await aha.addAhaClone(opts.dnsname, port=opts.port)
|
|
34
|
+
|
|
35
|
+
if opts.only_url:
|
|
36
|
+
outp.printf(curl)
|
|
37
|
+
else:
|
|
38
|
+
outp.printf(f'one-time use URL: {curl}')
|
|
39
|
+
return 0
|
|
40
|
+
|
|
41
|
+
except Exception as e:
|
|
42
|
+
mesg = repr(e)
|
|
43
|
+
if isinstance(e, s_exc.SynErr):
|
|
44
|
+
mesg = e.errinfo.get('mesg', repr(e))
|
|
45
|
+
|
|
46
|
+
outp.printf(f'ERROR: {mesg}')
|
|
47
|
+
return 1
|
|
48
|
+
|
|
49
|
+
if __name__ == '__main__': # pragma: no cover
|
|
50
|
+
sys.exit(asyncio.run(main(sys.argv[1:])))
|
synapse/tools/aha/enroll.py
CHANGED
|
@@ -76,7 +76,8 @@ async def main(argv, outp=s_output.stdout):
|
|
|
76
76
|
if isinstance(ahaurls, str):
|
|
77
77
|
ahaurls = (ahaurls,)
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
certname = f'{ahauser}@{ahanetw}'
|
|
80
|
+
ahaurls = set(s_telepath.modurl(ahaurls, certname=certname))
|
|
80
81
|
servers = teleyaml.get('aha:servers')
|
|
81
82
|
|
|
82
83
|
# repack the servers so lists are tuplized like values
|
synapse/tools/backup.py
CHANGED
|
@@ -148,7 +148,7 @@ def txnbackup(lmdbinfo, srcdir, dstdir, skipdirs=None):
|
|
|
148
148
|
logger.debug(f'Backup complete. Took [{tock-tick:.2f}] for [{srcdir}]')
|
|
149
149
|
return
|
|
150
150
|
|
|
151
|
-
def backup_lmdb(env, dstdir, txn=None):
|
|
151
|
+
def backup_lmdb(env: lmdb.Environment, dstdir: str, txn=None):
|
|
152
152
|
|
|
153
153
|
tick = time.time()
|
|
154
154
|
|
|
@@ -157,7 +157,7 @@ def backup_lmdb(env, dstdir, txn=None):
|
|
|
157
157
|
env.copy(dstdir, compact=True, txn=txn)
|
|
158
158
|
|
|
159
159
|
tock = time.time()
|
|
160
|
-
logger.info(f'backup took: {tock-tick:.2f} seconds')
|
|
160
|
+
logger.info(f'backup of: {env.path()} took: {tock-tick:.2f} seconds')
|
|
161
161
|
|
|
162
162
|
def main(argv):
|
|
163
163
|
args = parse_args(argv)
|