synapse 2.213.0__py311-none-any.whl → 2.215.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/cortex.py +37 -6
- synapse/daemon.py +6 -6
- synapse/exc.py +13 -1
- synapse/lib/aha.py +5 -0
- synapse/lib/ast.py +2 -6
- synapse/lib/boss.py +47 -2
- synapse/lib/cell.py +193 -3
- synapse/lib/certdir.py +44 -1
- synapse/lib/cmd.py +24 -0
- synapse/lib/coro.py +8 -2
- synapse/lib/drive.py +7 -2
- synapse/lib/jsonstor.py +4 -1
- synapse/lib/layer.py +3 -1
- synapse/lib/link.py +11 -3
- synapse/lib/schemas.py +1 -1
- synapse/lib/snap.py +76 -65
- synapse/lib/storm.py +2 -1
- synapse/lib/stormlib/imap.py +3 -2
- synapse/lib/stormlib/spooled.py +1 -0
- synapse/lib/task.py +1 -0
- synapse/lib/version.py +2 -2
- synapse/models/inet.py +5 -0
- synapse/models/infotech.py +45 -0
- synapse/tests/files/testpkg_build_docs/docs/bar.rst +15 -0
- synapse/tests/files/testpkg_build_docs/docs/foo.rst +4 -0
- synapse/tests/files/testpkg_build_docs/storm/commands/testcmd.storm +0 -0
- synapse/tests/files/testpkg_build_docs/storm/modules/apimod.storm +0 -0
- synapse/tests/files/testpkg_build_docs/storm/modules/testmod.storm +0 -0
- synapse/tests/files/testpkg_build_docs/storm/testcmd.storm +5 -0
- synapse/tests/files/testpkg_build_docs/testpkg.yaml +69 -0
- synapse/tests/test_cortex.py +20 -1
- synapse/tests/test_daemon.py +1 -1
- synapse/tests/test_exc.py +6 -0
- synapse/tests/test_lib_ast.py +69 -14
- synapse/tests/test_lib_boss.py +8 -0
- synapse/tests/test_lib_cell.py +104 -5
- synapse/tests/test_lib_certdir.py +8 -0
- synapse/tests/test_lib_coro.py +5 -0
- synapse/tests/test_lib_httpapi.py +10 -2
- synapse/tests/test_lib_jsonstor.py +45 -0
- synapse/tests/test_lib_layer.py +10 -0
- synapse/tests/test_lib_link.py +1 -1
- synapse/tests/test_lib_storm.py +121 -1
- synapse/tests/test_lib_stormlib_iters.py +1 -1
- synapse/tests/test_lib_stormlib_spooled.py +20 -0
- synapse/tests/test_lib_stormtypes.py +15 -0
- synapse/tests/test_lib_types.py +5 -1
- synapse/tests/test_model_inet.py +7 -0
- synapse/tests/test_model_infotech.py +31 -0
- synapse/tests/test_telepath.py +32 -5
- synapse/tests/test_tools_axon.py +304 -0
- synapse/tests/test_tools_cortex_layer.py +419 -0
- synapse/tests/test_tools_demote.py +114 -0
- synapse/tests/test_tools_pkgs_gendocs.py +100 -0
- synapse/tests/test_tools_shutdown.py +95 -0
- synapse/tests/test_utils.py +22 -1
- synapse/tests/utils.py +44 -29
- synapse/tools/aha/easycert.py +2 -0
- synapse/tools/aha/enroll.py +3 -0
- synapse/tools/axon/__init__.py +0 -0
- synapse/tools/axon/dump.py +155 -0
- synapse/tools/axon/load.py +89 -0
- synapse/tools/cortex/__init__.py +0 -0
- synapse/tools/cortex/layer/__init__.py +0 -0
- synapse/tools/cortex/layer/dump.py +184 -0
- synapse/tools/cortex/layer/load.py +129 -0
- synapse/tools/demote.py +52 -0
- synapse/tools/healthcheck.py +1 -1
- synapse/tools/pkgs/gendocs.py +176 -0
- synapse/tools/pkgs/pandoc_filter.py +79 -0
- synapse/tools/shutdown.py +52 -0
- {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/METADATA +1 -1
- {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/RECORD +76 -53
- {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/WHEEL +0 -0
- {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/licenses/LICENSE +0 -0
- {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/top_level.txt +0 -0
|
@@ -2999,6 +2999,21 @@ class StormTypesTest(s_test.SynTest):
|
|
|
2999
2999
|
self.eq((5, 'baz'), await core.callStorm('return($lib.queue.get(poptest).pop())'))
|
|
3000
3000
|
self.none(await core.callStorm('return($lib.queue.get(poptest).pop())'))
|
|
3001
3001
|
|
|
3002
|
+
# Coverage for the Cortex queue:del nexus handler
|
|
3003
|
+
name = 'deleteme'
|
|
3004
|
+
iden = s_common.guid()
|
|
3005
|
+
await core.addCoreQueue(
|
|
3006
|
+
name,
|
|
3007
|
+
{'name': name,
|
|
3008
|
+
'creator': core.auth.rootuser.iden,
|
|
3009
|
+
'created': s_common.now(),
|
|
3010
|
+
'iden': iden}
|
|
3011
|
+
)
|
|
3012
|
+
await core.auth.delAuthGate(f'queue:{name}')
|
|
3013
|
+
await core.delCoreQueue(name)
|
|
3014
|
+
with self.raises(s_exc.NoSuchName):
|
|
3015
|
+
await core.getCoreQueue(name)
|
|
3016
|
+
|
|
3002
3017
|
async def test_storm_node_data(self):
|
|
3003
3018
|
|
|
3004
3019
|
async with self.getTestCore() as core:
|
synapse/tests/test_lib_types.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import math
|
|
2
2
|
import decimal
|
|
3
|
+
import datetime
|
|
3
4
|
import synapse.exc as s_exc
|
|
4
5
|
import synapse.common as s_common
|
|
5
6
|
import synapse.datamodel as s_datamodel
|
|
@@ -1320,7 +1321,10 @@ class TypesTest(s_t_utils.SynTest):
|
|
|
1320
1321
|
nodes = await core.nodes('test:str:tick=201401*')
|
|
1321
1322
|
self.eq({node.ndef[1] for node in nodes}, {'a'})
|
|
1322
1323
|
|
|
1323
|
-
|
|
1324
|
+
utc = datetime.timezone.utc
|
|
1325
|
+
delta = datetime.datetime.now(tz=utc) - datetime.datetime(2014, 1, 1, tzinfo=utc)
|
|
1326
|
+
days = delta.days + 14
|
|
1327
|
+
nodes = await core.nodes(f'test:str:tick*range=("-{days} days", now)')
|
|
1324
1328
|
self.eq({node.ndef[1] for node in nodes}, {'a', 'b', 'c', 'd'})
|
|
1325
1329
|
|
|
1326
1330
|
opts = {'vars': {'tick': tick, 'tock': tock}}
|
synapse/tests/test_model_inet.py
CHANGED
|
@@ -3002,17 +3002,20 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3002
3002
|
:url="https://v.vtx.lk/slack"
|
|
3003
3003
|
:name="Synapse users slack"
|
|
3004
3004
|
:tenant={[ inet:service:tenant=({"id": "VS-31337"}) ]}
|
|
3005
|
+
:app={[ inet:service:app=({"id": "app00"}) ]}
|
|
3005
3006
|
]
|
|
3006
3007
|
'''
|
|
3007
3008
|
nodes = await core.nodes(q)
|
|
3008
3009
|
self.len(1, nodes)
|
|
3009
3010
|
self.nn(nodes[0].get('tenant'))
|
|
3011
|
+
self.nn(nodes[0].get('app'))
|
|
3010
3012
|
self.eq(nodes[0].ndef, ('inet:service:instance', s_common.guid(('vertex', 'slack'))))
|
|
3011
3013
|
self.eq(nodes[0].get('id'), 'T2XK1223Y')
|
|
3012
3014
|
self.eq(nodes[0].get('platform'), platform.ndef[1])
|
|
3013
3015
|
self.eq(nodes[0].get('url'), 'https://v.vtx.lk/slack')
|
|
3014
3016
|
self.eq(nodes[0].get('name'), 'synapse users slack')
|
|
3015
3017
|
platinst = nodes[0]
|
|
3018
|
+
app00 = nodes[0].get('app')
|
|
3016
3019
|
|
|
3017
3020
|
q = '''
|
|
3018
3021
|
[
|
|
@@ -3023,6 +3026,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3023
3026
|
:email=blackout@vertex.link
|
|
3024
3027
|
:profile={ gen.ps.contact.email vertex.employee blackout@vertex.link }
|
|
3025
3028
|
:tenant={[ inet:service:tenant=({"id": "VS-31337"}) ]}
|
|
3029
|
+
:app={[ inet:service:app=({"id": "a001"}) ]}
|
|
3026
3030
|
)
|
|
3027
3031
|
|
|
3028
3032
|
(inet:service:account=(visi, account, vertex, slack)
|
|
@@ -3037,6 +3041,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3037
3041
|
self.len(2, accounts)
|
|
3038
3042
|
|
|
3039
3043
|
self.nn(accounts[0].get('tenant'))
|
|
3044
|
+
self.nn(accounts[0].get('app'))
|
|
3040
3045
|
|
|
3041
3046
|
profiles = await core.nodes('ps:contact')
|
|
3042
3047
|
self.len(2, profiles)
|
|
@@ -3175,6 +3180,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3175
3180
|
:platform=$platiden
|
|
3176
3181
|
:instance=$instiden
|
|
3177
3182
|
:topic=' My Topic '
|
|
3183
|
+
:app={ inet:service:app:id=app00 }
|
|
3178
3184
|
]
|
|
3179
3185
|
'''
|
|
3180
3186
|
opts = {'vars': {
|
|
@@ -3185,6 +3191,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3185
3191
|
nodes = await core.nodes(q, opts=opts)
|
|
3186
3192
|
self.len(1, nodes)
|
|
3187
3193
|
self.eq(nodes[0].ndef, ('inet:service:channel', s_common.guid(('general', 'channel', 'vertex', 'slack'))))
|
|
3194
|
+
self.eq(nodes[0].get('app'), app00)
|
|
3188
3195
|
self.eq(nodes[0].get('name'), 'general')
|
|
3189
3196
|
self.eq(nodes[0].get('topic'), 'my topic')
|
|
3190
3197
|
self.eq(nodes[0].get('period'), (1420070400000, 9223372036854775807))
|
|
@@ -2438,3 +2438,34 @@ class InfotechModelTest(s_t_utils.SynTest):
|
|
|
2438
2438
|
self.eq(2, nodes[0].get('assets:vulns:preexisting'))
|
|
2439
2439
|
|
|
2440
2440
|
self.len(1, await core.nodes('it:sec:metrics -> ou:org +:name=vertex'))
|
|
2441
|
+
|
|
2442
|
+
async def test_infotech_windows(self):
|
|
2443
|
+
|
|
2444
|
+
async with self.getTestCore() as core:
|
|
2445
|
+
|
|
2446
|
+
nodes = await core.nodes('''
|
|
2447
|
+
[ it:os:windows:service=*
|
|
2448
|
+
:name=Woot
|
|
2449
|
+
:host=*
|
|
2450
|
+
:type=(0x20)
|
|
2451
|
+
:start=(0x20)
|
|
2452
|
+
:errorcontrol=(0x20)
|
|
2453
|
+
:displayname="Foo Bar Baz"
|
|
2454
|
+
:imagepath=c:/windows/system32/woot.exe
|
|
2455
|
+
:description="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
|
|
2456
|
+
]
|
|
2457
|
+
''')
|
|
2458
|
+
|
|
2459
|
+
self.len(1, nodes)
|
|
2460
|
+
self.eq(nodes[0].get('name'), 'woot')
|
|
2461
|
+
self.eq(nodes[0].get('type'), 0x20)
|
|
2462
|
+
self.eq(nodes[0].get('start'), 0x20)
|
|
2463
|
+
self.eq(nodes[0].get('errorcontrol'), 0x20)
|
|
2464
|
+
self.eq(nodes[0].get('displayname'), 'foo bar baz')
|
|
2465
|
+
self.eq(nodes[0].get('imagepath'), 'c:/windows/system32/woot.exe')
|
|
2466
|
+
self.eq(nodes[0].get('description'), 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
|
|
2467
|
+
|
|
2468
|
+
self.len(1, await core.nodes('it:os:windows:service -> it:host'))
|
|
2469
|
+
self.len(1, await core.nodes('it:os:windows:service -> file:path'))
|
|
2470
|
+
|
|
2471
|
+
self.len(1, await core.nodes('[ it:exec:proc=* :windows:service={ it:os:windows:service } ] -> it:os:windows:service'))
|
synapse/tests/test_telepath.py
CHANGED
|
@@ -110,7 +110,7 @@ class Foo:
|
|
|
110
110
|
|
|
111
111
|
def raze(self):
|
|
112
112
|
# test that SynErr makes it through
|
|
113
|
-
raise s_exc.
|
|
113
|
+
raise s_exc.SynErr(mesg='hehe', key='valu')
|
|
114
114
|
|
|
115
115
|
async def corovalu(self, x, y):
|
|
116
116
|
return x * 2 + y
|
|
@@ -305,11 +305,24 @@ class TeleTest(s_t_utils.SynTest):
|
|
|
305
305
|
genr = prox.agenrboom()
|
|
306
306
|
await self.asyncraises(s_exc.SynErr, genr.list())
|
|
307
307
|
|
|
308
|
-
|
|
308
|
+
with self.raises(s_exc.SynErr) as cm:
|
|
309
|
+
await prox.raze()
|
|
310
|
+
self.eq(cm.exception.get('mesg'), 'hehe')
|
|
311
|
+
self.eq(cm.exception.get('key'), 'valu')
|
|
309
312
|
|
|
310
|
-
|
|
313
|
+
with self.raises(s_exc.NoSuchMeth) as cm:
|
|
314
|
+
await prox.fake()
|
|
315
|
+
self.eq(cm.exception.get('mesg'), 'Foo has no method: fake.')
|
|
316
|
+
self.eq(cm.exception.get('name'), 'fake')
|
|
311
317
|
|
|
312
|
-
|
|
318
|
+
with self.raises(s_exc.NoSuchMeth) as cm:
|
|
319
|
+
await prox._fake()
|
|
320
|
+
self.eq(cm.exception.get('mesg'), 'Foo has no method: _fake.')
|
|
321
|
+
self.eq(cm.exception.get('name'), '_fake')
|
|
322
|
+
|
|
323
|
+
with self.raises(s_exc.NotMsgpackSafe) as cm:
|
|
324
|
+
await prox.boom()
|
|
325
|
+
self.isin("can not serialize 'Boom' object", cm.exception.get('mesg'))
|
|
313
326
|
|
|
314
327
|
# Fini'ing a daemon fini's proxies connected to it.
|
|
315
328
|
self.true(await s_coro.event_wait(evt, 2))
|
|
@@ -395,10 +408,12 @@ class TeleTest(s_t_utils.SynTest):
|
|
|
395
408
|
genr = prox.corogenr(3)
|
|
396
409
|
self.eq((0, 1, 2), await s_t_utils.alist(genr))
|
|
397
410
|
|
|
398
|
-
await self.asyncraises(s_exc.
|
|
411
|
+
await self.asyncraises(s_exc.SynErr, prox.raze())
|
|
399
412
|
|
|
400
413
|
await self.asyncraises(s_exc.NoSuchMeth, prox.fake())
|
|
401
414
|
|
|
415
|
+
await self.asyncraises(s_exc.NoSuchMeth, prox._fake())
|
|
416
|
+
|
|
402
417
|
await self.asyncraises(s_exc.SynErr, prox.boom())
|
|
403
418
|
|
|
404
419
|
# Fini'ing a daemon fini's proxies connected to it.
|
|
@@ -834,6 +849,18 @@ class TeleTest(s_t_utils.SynTest):
|
|
|
834
849
|
{'family': 'unix',
|
|
835
850
|
'addr': sockpath})
|
|
836
851
|
|
|
852
|
+
async def test_url_bad_cell_path(self):
|
|
853
|
+
with self.getTestDir() as dirn:
|
|
854
|
+
# Touch the sock path
|
|
855
|
+
s_common.genfile(dirn, 'newp', 'sock').close()
|
|
856
|
+
cell_url = f'cell://{dirn}/newp'
|
|
857
|
+
with self.raises(s_exc.LinkErr) as cm:
|
|
858
|
+
await s_telepath.openurl(cell_url)
|
|
859
|
+
self.isin('Cell path is not listening', cm.exception.get('mesg'))
|
|
860
|
+
with self.raises(s_exc.NoSuchPath) as cm:
|
|
861
|
+
await s_telepath.openurl(cell_url)
|
|
862
|
+
self.isin('Cell path does not exist', cm.exception.get('mesg'))
|
|
863
|
+
|
|
837
864
|
async def test_ipv6(self):
|
|
838
865
|
if s_common.envbool('CIRCLECI'):
|
|
839
866
|
self.skip('ipv6 listener is not supported in circleci')
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import os
|
|
3
|
+
import tarfile
|
|
4
|
+
|
|
5
|
+
from unittest import mock
|
|
6
|
+
|
|
7
|
+
import synapse.common as s_common
|
|
8
|
+
|
|
9
|
+
import synapse.tests.utils as s_t_utils
|
|
10
|
+
|
|
11
|
+
import synapse.tools.axon.dump as axon_dump
|
|
12
|
+
import synapse.tools.axon.load as axon_load
|
|
13
|
+
|
|
14
|
+
class AxonToolsTest(s_t_utils.SynTest):
|
|
15
|
+
|
|
16
|
+
async def test_axon_dump_and_load_url_handling(self):
|
|
17
|
+
with self.getTestDir() as testdir:
|
|
18
|
+
argv = ['--url', 'cell:///definitelynotarealpath/axon', '--offset', '0', testdir]
|
|
19
|
+
outp = self.getTestOutp()
|
|
20
|
+
self.eq(1, await axon_dump.main(argv, outp=outp))
|
|
21
|
+
outp.expect('ERROR')
|
|
22
|
+
outp.expect('Cell path does not exist')
|
|
23
|
+
|
|
24
|
+
with self.getTestDir() as testdir:
|
|
25
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
26
|
+
tarfile = os.path.join(testdir, 'dummy.0-1.tar.gz')
|
|
27
|
+
with open(tarfile, 'wb') as fd:
|
|
28
|
+
fd.write(b'dummy')
|
|
29
|
+
url = f'cell://baduser:badpass@/{axon.dirn}'
|
|
30
|
+
argv = ['--url', url, tarfile]
|
|
31
|
+
outp = self.getTestOutp()
|
|
32
|
+
self.eq(1, await axon_load.main(argv, outp=outp))
|
|
33
|
+
outp.expect('No such user')
|
|
34
|
+
|
|
35
|
+
with self.getTestDir() as testdir:
|
|
36
|
+
tarfile = os.path.join(testdir, 'dummy.0-1.tar.gz')
|
|
37
|
+
with open(tarfile, 'wb') as fd:
|
|
38
|
+
fd.write(b'dummy')
|
|
39
|
+
argv = ['--url', 'cell:///definitelynotarealpath/axon', tarfile]
|
|
40
|
+
outp = self.getTestOutp()
|
|
41
|
+
self.eq(1, await axon_load.main(argv, outp=outp))
|
|
42
|
+
outp.expect('ERROR')
|
|
43
|
+
outp.expect('Cell path does not exist')
|
|
44
|
+
|
|
45
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
46
|
+
dumpdir = os.path.join(testdir, 'dumpdir')
|
|
47
|
+
os.makedirs(dumpdir)
|
|
48
|
+
url = f'cell://baduser:badpass@/{axon.dirn}'
|
|
49
|
+
argv = ['--url', url, '--offset', '0', dumpdir]
|
|
50
|
+
outp = self.getTestOutp()
|
|
51
|
+
self.eq(1, await axon_dump.main(argv, outp=outp))
|
|
52
|
+
outp.expect('No such user')
|
|
53
|
+
|
|
54
|
+
async def test_axon_dump_and_load(self):
|
|
55
|
+
with self.getTestDir() as testdir:
|
|
56
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon0')) as axon0:
|
|
57
|
+
blobs = [b'foo', b'bar', b'baz' * 1000]
|
|
58
|
+
sha2s = []
|
|
59
|
+
for blob in blobs:
|
|
60
|
+
size, sha2 = await axon0.put(blob)
|
|
61
|
+
sha2s.append((size, sha2, blob))
|
|
62
|
+
dumpdir = os.path.join(testdir, 'dumpdir')
|
|
63
|
+
os.makedirs(dumpdir)
|
|
64
|
+
argv = [
|
|
65
|
+
'--url', f'cell:///{axon0.dirn}',
|
|
66
|
+
'--offset', '0',
|
|
67
|
+
dumpdir,
|
|
68
|
+
]
|
|
69
|
+
self.eq(0, await axon_dump.main(argv))
|
|
70
|
+
files = os.listdir(dumpdir)
|
|
71
|
+
self.true(files, 'No dump file created')
|
|
72
|
+
|
|
73
|
+
tarfiles = sorted([os.path.join(dumpdir, f) for f in files if f.endswith('.tar.gz')])
|
|
74
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon1')) as axon1:
|
|
75
|
+
argv = ['--url', f'cell:///{axon1.dirn}'] + tarfiles
|
|
76
|
+
self.eq(0, await axon_load.main(argv))
|
|
77
|
+
for size, sha2, blob in sha2s:
|
|
78
|
+
self.true(await axon1.has(sha2))
|
|
79
|
+
out = b''
|
|
80
|
+
async for byts in axon1.get(sha2):
|
|
81
|
+
out += byts
|
|
82
|
+
self.eq(out, blob)
|
|
83
|
+
|
|
84
|
+
async def test_dump_blob_size_mismatch(self):
|
|
85
|
+
with self.getTestDir() as testdir:
|
|
86
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
87
|
+
size, sha2 = await axon.put(b'hello world')
|
|
88
|
+
dumpdir = os.path.join(testdir, 'dumpdir')
|
|
89
|
+
os.makedirs(dumpdir)
|
|
90
|
+
orig_get = axon.get
|
|
91
|
+
async def bad_get(sha2arg, **kwargs):
|
|
92
|
+
if sha2arg == sha2:
|
|
93
|
+
yield b'hello' # corrupt it
|
|
94
|
+
else:
|
|
95
|
+
async for byts in orig_get(sha2arg):
|
|
96
|
+
yield byts
|
|
97
|
+
axon.get = bad_get
|
|
98
|
+
argv = ['--url', f'cell:///{axon.dirn}', '--offset', '0', dumpdir]
|
|
99
|
+
outp = self.getTestOutp()
|
|
100
|
+
self.eq(1, await axon_dump.main(argv, outp=outp))
|
|
101
|
+
outp.expect('Blob size mismatch')
|
|
102
|
+
|
|
103
|
+
async def test_dump_not_axon_cell(self):
|
|
104
|
+
with self.getTestDir() as testdir:
|
|
105
|
+
async with self.getTestCore() as core:
|
|
106
|
+
curl = core.getLocalUrl()
|
|
107
|
+
argv = ['--url', curl, testdir]
|
|
108
|
+
outp = self.getTestOutp()
|
|
109
|
+
self.eq(1, await axon_dump.main(argv, outp=outp))
|
|
110
|
+
outp.expect('only works on axon')
|
|
111
|
+
|
|
112
|
+
async def test_dump_outdir_is_not_directory(self):
|
|
113
|
+
with self.getTestDir() as testdir:
|
|
114
|
+
outpath = os.path.join(testdir, 'notadir')
|
|
115
|
+
with open(outpath, 'w') as fd:
|
|
116
|
+
fd.write('not a directory')
|
|
117
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
118
|
+
argv = ['--url', f'cell:///{axon.dirn}', '--offset', '0', outpath]
|
|
119
|
+
outp = self.getTestOutp()
|
|
120
|
+
self.eq(1, await axon_dump.main(argv, outp=outp))
|
|
121
|
+
outp.expect('exists but is not a directory')
|
|
122
|
+
|
|
123
|
+
async def test_dump_rotate_size_and_load(self):
|
|
124
|
+
with self.getTestDir() as testdir:
|
|
125
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
126
|
+
blobs = [os.urandom(1024) for _ in range(10)]
|
|
127
|
+
sha2s = []
|
|
128
|
+
for blob in blobs:
|
|
129
|
+
size, sha2 = await axon.put(blob)
|
|
130
|
+
sha2s.append((size, sha2, blob))
|
|
131
|
+
dumpdir = os.path.join(testdir, 'dumpdir')
|
|
132
|
+
os.makedirs(dumpdir)
|
|
133
|
+
argv = ['--url', f'cell:///{axon.dirn}', '--offset', '0', '--rotate-size', '2048', dumpdir]
|
|
134
|
+
outp = self.getTestOutp()
|
|
135
|
+
self.eq(0, await axon_dump.main(argv, outp=outp))
|
|
136
|
+
|
|
137
|
+
tarfiles = sorted([os.path.join(dumpdir, f) for f in os.listdir(dumpdir) if f.endswith('.tar.gz')])
|
|
138
|
+
self.true(len(tarfiles) > 1)
|
|
139
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon2')) as axon2:
|
|
140
|
+
outp = self.getTestOutp()
|
|
141
|
+
argv = ['--url', f'cell:///{axon2.dirn}'] + tarfiles
|
|
142
|
+
self.eq(0, await axon_load.main(argv, outp=outp))
|
|
143
|
+
for size, sha2, blob in sha2s:
|
|
144
|
+
self.true(await axon2.has(sha2))
|
|
145
|
+
out = b''
|
|
146
|
+
async for byts in axon2.get(sha2):
|
|
147
|
+
out += byts
|
|
148
|
+
self.eq(out, blob)
|
|
149
|
+
|
|
150
|
+
async def test_dump_tempfile_rollover(self):
|
|
151
|
+
with self.getTestDir() as testdir:
|
|
152
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
153
|
+
n = 128
|
|
154
|
+
blobs = [os.urandom(n) for n in range(n)]
|
|
155
|
+
sha2s = []
|
|
156
|
+
for blob in blobs:
|
|
157
|
+
size, sha2 = await axon.put(blob)
|
|
158
|
+
sha2s.append((size, sha2, blob))
|
|
159
|
+
dumpdir = os.path.join(testdir, 'dumpdir')
|
|
160
|
+
os.makedirs(dumpdir)
|
|
161
|
+
argv = ['--url', f'cell:///{axon.dirn}', dumpdir]
|
|
162
|
+
outp = self.getTestOutp()
|
|
163
|
+
|
|
164
|
+
# Patch the SppoledTemporaryFile rollover size while dumping files.
|
|
165
|
+
with mock.patch('synapse.tools.axon.dump.MAX_SPOOL_SIZE', n / 2):
|
|
166
|
+
self.eq(0, await axon_dump.main(argv, outp=outp))
|
|
167
|
+
|
|
168
|
+
tarfiles = sorted([os.path.join(dumpdir, f) for f in os.listdir(dumpdir) if f.endswith('.tar.gz')])
|
|
169
|
+
self.len(1, tarfiles)
|
|
170
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon2')) as axon2:
|
|
171
|
+
outp = self.getTestOutp()
|
|
172
|
+
argv = ['--url', f'cell:///{axon2.dirn}'] + tarfiles
|
|
173
|
+
self.eq(0, await axon_load.main(argv, outp=outp))
|
|
174
|
+
for size, sha2, blob in sha2s:
|
|
175
|
+
self.true(await axon2.has(sha2))
|
|
176
|
+
out = b''
|
|
177
|
+
async for byts in axon2.get(sha2):
|
|
178
|
+
out += byts
|
|
179
|
+
self.eq(out, blob)
|
|
180
|
+
|
|
181
|
+
async def test_dump_statefile(self):
|
|
182
|
+
with self.getTestDir() as testdir:
|
|
183
|
+
async with self.getTestAxon(dirn=testdir) as axon:
|
|
184
|
+
blob_data = b'blobdata'
|
|
185
|
+
await axon.put(blob_data)
|
|
186
|
+
outdir = os.path.join(testdir, 'out')
|
|
187
|
+
os.makedirs(outdir)
|
|
188
|
+
statefile = os.path.join(testdir, 'state.yaml')
|
|
189
|
+
|
|
190
|
+
argv = ['--url', axon.getLocalUrl(), '--statefile', statefile, outdir]
|
|
191
|
+
outp = self.getTestOutp()
|
|
192
|
+
self.eq(0, await axon_dump.main(argv, outp=outp))
|
|
193
|
+
self.true(os.path.isfile(statefile))
|
|
194
|
+
state = s_common.yamlload(statefile)
|
|
195
|
+
self.isin('offset:next', state)
|
|
196
|
+
|
|
197
|
+
s_common.yamlsave({'offset:next': 123}, statefile)
|
|
198
|
+
outp = self.getTestOutp()
|
|
199
|
+
self.eq(0, await axon_dump.main(argv, outp=outp))
|
|
200
|
+
self.true(os.path.isfile(statefile))
|
|
201
|
+
state = s_common.yamlload(statefile)
|
|
202
|
+
self.isin('offset:next', state)
|
|
203
|
+
self.ne(state['offset:next'], 123)
|
|
204
|
+
|
|
205
|
+
statedir = os.path.join(testdir, 'statedir')
|
|
206
|
+
os.makedirs(statedir)
|
|
207
|
+
argv = ['--url', axon.getLocalUrl(), '--statefile', statedir, outdir]
|
|
208
|
+
outp = self.getTestOutp()
|
|
209
|
+
self.eq(0, await axon_dump.main(argv, outp=outp))
|
|
210
|
+
cellinfo = await axon.getCellInfo()
|
|
211
|
+
celliden = cellinfo['cell']['iden']
|
|
212
|
+
statefile_path = os.path.join(statedir, f'{celliden}.yaml')
|
|
213
|
+
self.true(os.path.isfile(statefile_path))
|
|
214
|
+
state = s_common.yamlload(statefile_path)
|
|
215
|
+
self.isin('offset:next', state)
|
|
216
|
+
|
|
217
|
+
async def test_load_blobs_path_does_not_exist(self):
|
|
218
|
+
with self.getTestDir() as testdir:
|
|
219
|
+
missing = os.path.join(testdir, 'doesnotexist')
|
|
220
|
+
argv = ['--url', 'cell:///definitelynotarealpath/axon', missing]
|
|
221
|
+
outp = self.getTestOutp()
|
|
222
|
+
self.eq(1, await axon_load.main(argv, outp=outp))
|
|
223
|
+
outp.expect('ERROR: Cell path does not exist')
|
|
224
|
+
|
|
225
|
+
async def test_load_continue_and_invalid_blob(self):
|
|
226
|
+
with self.getTestDir() as testdir:
|
|
227
|
+
tarpath = os.path.join(testdir, 'test1.tar.gz')
|
|
228
|
+
with tarfile.open(tarpath, 'w:gz') as tar:
|
|
229
|
+
info = tarfile.TarInfo('notablob.txt')
|
|
230
|
+
data = b'not a blob'
|
|
231
|
+
info.size = len(data)
|
|
232
|
+
tar.addfile(info, io.BytesIO(data))
|
|
233
|
+
info2 = tarfile.TarInfo('invalidblobname.blob')
|
|
234
|
+
data2 = b'data'
|
|
235
|
+
info2.size = len(data2)
|
|
236
|
+
tar.addfile(info2, io.BytesIO(data2))
|
|
237
|
+
|
|
238
|
+
orig_uhex = s_common.uhex
|
|
239
|
+
def fake_uhex(val):
|
|
240
|
+
if val == 'invalidblobname':
|
|
241
|
+
raise Exception('bad hex')
|
|
242
|
+
return orig_uhex(val)
|
|
243
|
+
s_common.uhex = fake_uhex
|
|
244
|
+
|
|
245
|
+
outp = self.getTestOutp()
|
|
246
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
247
|
+
argv = ['--url', axon.getLocalUrl(), tarpath]
|
|
248
|
+
self.eq(0, await axon_load.main(argv, outp=outp))
|
|
249
|
+
s_common.uhex = orig_uhex
|
|
250
|
+
outp.expect('Skipping invalid blob filename')
|
|
251
|
+
|
|
252
|
+
async def test_load_failed_to_extract(self):
|
|
253
|
+
with self.getTestDir() as testdir:
|
|
254
|
+
tarpath = os.path.join(testdir, 'test3.tar.gz')
|
|
255
|
+
with tarfile.open(tarpath, 'w:gz') as tar:
|
|
256
|
+
info = tarfile.TarInfo('deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef.blob')
|
|
257
|
+
info.type = tarfile.DIRTYPE
|
|
258
|
+
tar.addfile(info)
|
|
259
|
+
outp = self.getTestOutp()
|
|
260
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
261
|
+
argv = ['--url', axon.getLocalUrl(), tarpath]
|
|
262
|
+
self.eq(0, await axon_load.main(argv, outp=outp))
|
|
263
|
+
outp.expect('Failed to extract')
|
|
264
|
+
|
|
265
|
+
async def test_load_not_axon_cell(self):
|
|
266
|
+
with self.getTestDir() as testdir:
|
|
267
|
+
async with self.getTestCore() as core:
|
|
268
|
+
curl = core.getLocalUrl()
|
|
269
|
+
dumpdir = os.path.join(testdir, 'dumpdir')
|
|
270
|
+
os.makedirs(dumpdir)
|
|
271
|
+
argv = ['--url', curl, dumpdir]
|
|
272
|
+
outp = self.getTestOutp()
|
|
273
|
+
self.eq(1, await axon_load.main(argv, outp=outp))
|
|
274
|
+
outp.expect('only works on axon')
|
|
275
|
+
|
|
276
|
+
async def test_load_oserror_extracting_blob(self):
|
|
277
|
+
with self.getTestDir() as testdir:
|
|
278
|
+
tarpath = os.path.join(testdir, 'test_oserror.tar.gz')
|
|
279
|
+
with tarfile.open(tarpath, 'w:gz') as tar:
|
|
280
|
+
info = tarfile.TarInfo('deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef.blob')
|
|
281
|
+
data = b'12345'
|
|
282
|
+
info.size = len(data)
|
|
283
|
+
tar.addfile(info, io.BytesIO(data))
|
|
284
|
+
outp = self.getTestOutp()
|
|
285
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
286
|
+
with mock.patch('tarfile.TarFile.extractfile', side_effect=OSError("simulated extraction error")):
|
|
287
|
+
argv = ['--url', axon.getLocalUrl(), tarpath]
|
|
288
|
+
self.eq(0, await axon_load.main(argv, outp=outp))
|
|
289
|
+
outp.expect('WARNING: Error extracting')
|
|
290
|
+
|
|
291
|
+
async def test_load_skipping_existing_blob(self):
|
|
292
|
+
with self.getTestDir() as testdir:
|
|
293
|
+
async with self.getTestAxon(dirn=os.path.join(testdir, 'axon')) as axon:
|
|
294
|
+
blob = b'foo'
|
|
295
|
+
size, sha2 = await axon.put(blob)
|
|
296
|
+
tarpath = os.path.join(testdir, 'test2.tar.gz')
|
|
297
|
+
with tarfile.open(tarpath, 'w:gz') as tar:
|
|
298
|
+
info = tarfile.TarInfo(f'{s_common.ehex(sha2)}.blob')
|
|
299
|
+
info.size = len(blob)
|
|
300
|
+
tar.addfile(info, io.BytesIO(blob))
|
|
301
|
+
outp = self.getTestOutp()
|
|
302
|
+
argv = ['--url', axon.getLocalUrl(), tarpath]
|
|
303
|
+
self.eq(0, await axon_load.main(argv, outp=outp))
|
|
304
|
+
outp.expect('Skipping existing blob')
|