synapse 2.195.0__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 +13 -6
- 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 +124 -6
- 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_nexus.py +24 -2
- 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.0.dist-info → synapse-2.196.0.dist-info}/METADATA +1 -1
- {synapse-2.195.0.dist-info → synapse-2.196.0.dist-info}/RECORD +46 -43
- {synapse-2.195.0.dist-info → synapse-2.196.0.dist-info}/LICENSE +0 -0
- {synapse-2.195.0.dist-info → synapse-2.196.0.dist-info}/WHEEL +0 -0
- {synapse-2.195.0.dist-info → synapse-2.196.0.dist-info}/top_level.txt +0 -0
|
@@ -3,6 +3,7 @@ import bz2
|
|
|
3
3
|
import gzip
|
|
4
4
|
import json
|
|
5
5
|
import base64
|
|
6
|
+
import struct
|
|
6
7
|
import asyncio
|
|
7
8
|
import hashlib
|
|
8
9
|
import binascii
|
|
@@ -6467,13 +6468,29 @@ words\tword\twrd'''
|
|
|
6467
6468
|
async with self.getTestCore() as core:
|
|
6468
6469
|
|
|
6469
6470
|
viewiden = await core.callStorm('return($lib.view.get().fork().iden)')
|
|
6470
|
-
|
|
6471
|
+
q = '[ ou:org=* :name=foobar +#hehe ] $node.data.set(foo, bar) return($node.iden())'
|
|
6472
|
+
basenode = await core.callStorm(q)
|
|
6471
6473
|
|
|
6472
6474
|
opts = {'view': viewiden}
|
|
6473
|
-
nodeiden = await core.callStorm('
|
|
6475
|
+
nodeiden = await core.callStorm('''
|
|
6476
|
+
[ ou:org=* :name=foobar +#hehe ]
|
|
6477
|
+
$node.data.set(foo, bar)
|
|
6478
|
+
return($node.iden())
|
|
6479
|
+
''', opts=opts)
|
|
6480
|
+
|
|
6481
|
+
nodeiden2 = await core.callStorm('[test:str=yup] $node.data.set(foo, yup) return ($node.iden())',
|
|
6482
|
+
opts=opts)
|
|
6474
6483
|
|
|
6475
6484
|
self.len(2, await core.nodes('ou:org +:name=foobar +#hehe', opts=opts))
|
|
6476
6485
|
|
|
6486
|
+
nodes = await core.nodes('yield $lib.layer.get().liftByNodeData(foo)', opts=opts)
|
|
6487
|
+
self.len(2, nodes)
|
|
6488
|
+
self.eq(set((nodeiden, nodeiden2)), {node.iden() for node in nodes})
|
|
6489
|
+
|
|
6490
|
+
nodes = await core.nodes('yield $lib.layer.get().liftByNodeData(foo)')
|
|
6491
|
+
self.len(1, nodes)
|
|
6492
|
+
self.eq(nodes[0].iden(), basenode)
|
|
6493
|
+
|
|
6477
6494
|
nodes = await core.nodes('yield $lib.layer.get().liftByProp(ou:org)', opts=opts)
|
|
6478
6495
|
self.len(1, nodes)
|
|
6479
6496
|
self.eq(nodes[0].iden(), nodeiden)
|
|
@@ -6487,7 +6504,7 @@ words\tword\twrd'''
|
|
|
6487
6504
|
self.eq(nodes[0].iden(), nodeiden)
|
|
6488
6505
|
|
|
6489
6506
|
nodes = await core.nodes('yield $lib.layer.get().liftByProp(".created")', opts=opts)
|
|
6490
|
-
self.len(
|
|
6507
|
+
self.len(2, nodes)
|
|
6491
6508
|
self.eq(nodes[0].iden(), nodeiden)
|
|
6492
6509
|
|
|
6493
6510
|
nodes = await core.nodes('yield $lib.layer.get().liftByTag(hehe)', opts=opts)
|
|
@@ -7084,3 +7101,73 @@ words\tword\twrd'''
|
|
|
7084
7101
|
|
|
7085
7102
|
with self.raises(s_exc.BadState):
|
|
7086
7103
|
await core.callStorm(merging)
|
|
7104
|
+
|
|
7105
|
+
async def test_storm_lib_axon_read_unpack(self):
|
|
7106
|
+
|
|
7107
|
+
async with self.getTestCore() as core:
|
|
7108
|
+
|
|
7109
|
+
visi = await core.auth.addUser('visi')
|
|
7110
|
+
|
|
7111
|
+
orig_axoninfo = core.axoninfo
|
|
7112
|
+
core.axoninfo = {'features': {}}
|
|
7113
|
+
data = struct.pack('>Q', 1)
|
|
7114
|
+
size, sha256 = await core.axon.put(data)
|
|
7115
|
+
sha256_s = s_common.ehex(sha256)
|
|
7116
|
+
q = 'return($lib.axon.unpack($sha256, fmt=">Q"))'
|
|
7117
|
+
await self.asyncraises(s_exc.FeatureNotSupported,
|
|
7118
|
+
core.callStorm(q, opts={'vars': {'sha256': sha256_s}}))
|
|
7119
|
+
core.axoninfo = orig_axoninfo
|
|
7120
|
+
|
|
7121
|
+
data = b'vertex.link'
|
|
7122
|
+
size, sha256 = await core.axon.put(data)
|
|
7123
|
+
sha256_s = s_common.ehex(sha256)
|
|
7124
|
+
|
|
7125
|
+
_, emptyhash = await core.axon.put(b'')
|
|
7126
|
+
emptyhash = s_common.ehex(emptyhash)
|
|
7127
|
+
|
|
7128
|
+
opts = {'user': visi.iden, 'vars': {'sha256': sha256_s, 'emptyhash': emptyhash}}
|
|
7129
|
+
await self.asyncraises(s_exc.AuthDeny,
|
|
7130
|
+
core.callStorm('return($lib.axon.read($sha256, offs=3, size=3))', opts=opts))
|
|
7131
|
+
await visi.addRule((True, ('storm', 'lib', 'axon', 'get')))
|
|
7132
|
+
|
|
7133
|
+
q = 'return($lib.axon.read($sha256, offs=3, size=3))'
|
|
7134
|
+
self.eq(b'tex', await core.callStorm(q, opts=opts))
|
|
7135
|
+
q = 'return($lib.axon.read($sha256, offs=7, size=4))'
|
|
7136
|
+
self.eq(b'link', await core.callStorm(q, opts=opts))
|
|
7137
|
+
q = 'return($lib.axon.read($sha256, offs=11, size=1))'
|
|
7138
|
+
self.eq(b'', await core.callStorm(q, opts=opts))
|
|
7139
|
+
|
|
7140
|
+
q = 'return($lib.axon.read($emptyhash))'
|
|
7141
|
+
self.eq(b'', await core.callStorm(q, opts=opts))
|
|
7142
|
+
|
|
7143
|
+
q = 'return($lib.axon.read($sha256, size=0))'
|
|
7144
|
+
await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
|
|
7145
|
+
q = 'return($lib.axon.read($sha256, offs=-1, size=1))'
|
|
7146
|
+
await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
|
|
7147
|
+
q = 'return($lib.axon.read($sha256, size=2097152))'
|
|
7148
|
+
await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
|
|
7149
|
+
|
|
7150
|
+
intdata = struct.pack('>QQQ', 1, 2, 3)
|
|
7151
|
+
size, sha256 = await core.axon.put(intdata)
|
|
7152
|
+
sha256_s = s_common.ehex(sha256)
|
|
7153
|
+
opts = {'user': visi.iden, 'vars': {'sha256': sha256_s}}
|
|
7154
|
+
|
|
7155
|
+
await visi.delRule((True, ('storm', 'lib', 'axon', 'get')))
|
|
7156
|
+
q = 'return($lib.axon.unpack($sha256, fmt=">Q"))'
|
|
7157
|
+
await self.asyncraises(s_exc.AuthDeny, core.callStorm(q, opts=opts))
|
|
7158
|
+
await visi.addRule((True, ('storm', 'lib', 'axon', 'get')))
|
|
7159
|
+
|
|
7160
|
+
q = 'return($lib.axon.unpack($sha256, fmt=">Q"))'
|
|
7161
|
+
self.eq((1,), await core.callStorm(q, opts=opts))
|
|
7162
|
+
q = 'return($lib.axon.unpack($sha256, fmt=">Q", offs=8))'
|
|
7163
|
+
self.eq((2,), await core.callStorm(q, opts=opts))
|
|
7164
|
+
q = 'return($lib.axon.unpack($sha256, fmt=">Q", offs=16))'
|
|
7165
|
+
self.eq((3,), await core.callStorm(q, opts=opts))
|
|
7166
|
+
q = 'return($lib.axon.unpack($sha256, fmt=">QQ", offs=8))'
|
|
7167
|
+
self.eq((2, 3), await core.callStorm(q, opts=opts))
|
|
7168
|
+
|
|
7169
|
+
q = 'return($lib.axon.unpack($sha256, fmt="not a valid format"))'
|
|
7170
|
+
await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
|
|
7171
|
+
|
|
7172
|
+
q = 'return($lib.axon.unpack($sha256, fmt=">Q", offs=24))'
|
|
7173
|
+
await self.asyncraises(s_exc.BadDataValu, core.callStorm(q, opts=opts))
|
synapse/tests/test_model_base.py
CHANGED
|
@@ -227,6 +227,7 @@ class BaseTest(s_t_utils.SynTest):
|
|
|
227
227
|
:name="FOO Bar"
|
|
228
228
|
:type=osint
|
|
229
229
|
:url="https://foo.bar/index.html"
|
|
230
|
+
:ingest:cursor="Woot Woot "
|
|
230
231
|
:ingest:latest=20241205
|
|
231
232
|
:ingest:offset=17
|
|
232
233
|
]
|
|
@@ -238,6 +239,7 @@ class BaseTest(s_t_utils.SynTest):
|
|
|
238
239
|
self.eq(sorc.get('name'), 'foo bar')
|
|
239
240
|
self.eq(sorc.get('url'), 'https://foo.bar/index.html')
|
|
240
241
|
self.eq(sorc.get('ingest:offset'), 17)
|
|
242
|
+
self.eq(sorc.get('ingest:cursor'), 'Woot Woot ')
|
|
241
243
|
self.eq(sorc.get('ingest:latest'), 1733356800000)
|
|
242
244
|
|
|
243
245
|
valu = (sorc.ndef[1], ('inet:fqdn', 'woot.com'))
|
|
@@ -342,6 +342,7 @@ class InfotechModelTest(s_t_utils.SynTest):
|
|
|
342
342
|
:verdict=suspicious
|
|
343
343
|
:scanner={[ it:prod:softver=* :name="visi scan" ]}
|
|
344
344
|
:scanner:name="visi scan"
|
|
345
|
+
:categories=("Foo Bar", "baz faz")
|
|
345
346
|
:signame=omgwtfbbq
|
|
346
347
|
:target:file=*
|
|
347
348
|
:target:proc={[ it:exec:proc=* :cmd="foo.exe --bar" ]}
|
|
@@ -367,6 +368,7 @@ class InfotechModelTest(s_t_utils.SynTest):
|
|
|
367
368
|
self.eq(0x01020304, nodes[0].get('target:ipv4'))
|
|
368
369
|
self.eq('::1', nodes[0].get('target:ipv6'))
|
|
369
370
|
self.eq('omgwtfbbq', nodes[0].get('signame'))
|
|
371
|
+
self.eq(('baz faz', 'foo bar'), nodes[0].get('categories'))
|
|
370
372
|
|
|
371
373
|
self.len(1, await core.nodes('it:av:scan:result:scanner:name="visi scan" -> it:host'))
|
|
372
374
|
self.len(1, await core.nodes('it:av:scan:result:scanner:name="visi scan" -> inet:url'))
|
|
@@ -617,11 +619,36 @@ class InfotechModelTest(s_t_utils.SynTest):
|
|
|
617
619
|
node = nodes[0]
|
|
618
620
|
self.eq(node.ndef, ('it:dev:int', 1640531528))
|
|
619
621
|
|
|
620
|
-
nodes = await core.nodes('[
|
|
622
|
+
nodes = await core.nodes('''[
|
|
623
|
+
it:sec:cve=CVE-2013-9999
|
|
624
|
+
:desc="Some words."
|
|
625
|
+
|
|
626
|
+
:nist:nvd:source=NistSource
|
|
627
|
+
:nist:nvd:published=2021-10-11
|
|
628
|
+
:nist:nvd:modified=2021-10-11
|
|
629
|
+
|
|
630
|
+
:cisa:kev:name=KevName
|
|
631
|
+
:cisa:kev:desc=KevDesc
|
|
632
|
+
:cisa:kev:action=KevAction
|
|
633
|
+
:cisa:kev:vendor=KevVendor
|
|
634
|
+
:cisa:kev:product=KevProduct
|
|
635
|
+
:cisa:kev:added=2022-01-02
|
|
636
|
+
:cisa:kev:duedate=2022-01-02
|
|
637
|
+
]''')
|
|
621
638
|
self.len(1, nodes)
|
|
622
639
|
node = nodes[0]
|
|
623
640
|
self.eq(node.ndef, ('it:sec:cve', 'cve-2013-9999'))
|
|
624
641
|
self.eq(node.get('desc'), 'Some words.')
|
|
642
|
+
self.eq(node.get('nist:nvd:source'), 'nistsource')
|
|
643
|
+
self.eq(node.get('nist:nvd:published'), 1633910400000)
|
|
644
|
+
self.eq(node.get('nist:nvd:modified'), 1633910400000)
|
|
645
|
+
self.eq(node.get('cisa:kev:name'), 'KevName')
|
|
646
|
+
self.eq(node.get('cisa:kev:desc'), 'KevDesc')
|
|
647
|
+
self.eq(node.get('cisa:kev:action'), 'KevAction')
|
|
648
|
+
self.eq(node.get('cisa:kev:vendor'), 'kevvendor')
|
|
649
|
+
self.eq(node.get('cisa:kev:product'), 'kevproduct')
|
|
650
|
+
self.eq(node.get('cisa:kev:added'), 1641081600000)
|
|
651
|
+
self.eq(node.get('cisa:kev:duedate'), 1641081600000)
|
|
625
652
|
|
|
626
653
|
nodes = await core.nodes('[it:sec:cve=$valu]', opts={'vars': {'valu': 'CVE\u20122013\u20131138'}})
|
|
627
654
|
self.len(1, nodes)
|
synapse/tests/test_model_orgs.py
CHANGED
|
@@ -640,6 +640,7 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
640
640
|
ou:contest:result=(*, *)
|
|
641
641
|
:rank=1
|
|
642
642
|
:score=20
|
|
643
|
+
:period=(20250101, 20250102)
|
|
643
644
|
:url=http://vertex.link/contest/result
|
|
644
645
|
]''')
|
|
645
646
|
self.len(1, nodes)
|
|
@@ -647,6 +648,7 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
647
648
|
self.nn(nodes[0].get('participant'))
|
|
648
649
|
self.eq(1, nodes[0].get('rank'))
|
|
649
650
|
self.eq(20, nodes[0].get('score'))
|
|
651
|
+
self.eq((1735689600000, 1735776000000), nodes[0].get('period'))
|
|
650
652
|
self.eq('http://vertex.link/contest/result', nodes[0].get('url'))
|
|
651
653
|
self.len(1, await core.nodes('ou:contest:result -> ps:contact'))
|
|
652
654
|
self.len(1, await core.nodes('ou:contest:result -> ou:contest'))
|
synapse/tests/test_model_risk.py
CHANGED
|
@@ -111,12 +111,14 @@ class RiskModelTest(s_t_utils.SynTest):
|
|
|
111
111
|
:cvss:v3 ?= "newp3.1"
|
|
112
112
|
:priority=high
|
|
113
113
|
:severity=high
|
|
114
|
+
:tag=cno.vuln.woot
|
|
114
115
|
]''')
|
|
115
116
|
|
|
116
117
|
self.none(node.get('cvss:v2'))
|
|
117
118
|
self.none(node.get('cvss:v3'))
|
|
118
119
|
self.eq(40, node.get('severity'))
|
|
119
120
|
self.eq(40, node.get('priority'))
|
|
121
|
+
self.eq('cno.vuln.woot', node.get('tag'))
|
|
120
122
|
|
|
121
123
|
with self.raises(s_exc.BadTypeValu):
|
|
122
124
|
node = await addNode(f'''[
|
|
@@ -110,6 +110,7 @@ class TransportTest(s_test.SynTest):
|
|
|
110
110
|
self.nn(vessel.get('operator'))
|
|
111
111
|
|
|
112
112
|
self.len(1, await core.nodes('transport:sea:vessel:imo^="IMO 123"'))
|
|
113
|
+
self.len(1, await core.nodes('transport:sea:vessel :name -> entity:name'))
|
|
113
114
|
self.len(1, await core.nodes('transport:sea:vessel -> transport:sea:vessel:type:taxonomy'))
|
|
114
115
|
|
|
115
116
|
seatelem = (await core.nodes('''[
|
synapse/tests/test_telepath.py
CHANGED
|
@@ -54,6 +54,9 @@ class Beep:
|
|
|
54
54
|
def beep(self):
|
|
55
55
|
return f'{self.path}: beep'
|
|
56
56
|
|
|
57
|
+
def genbeep(self):
|
|
58
|
+
yield self.beep()
|
|
59
|
+
|
|
57
60
|
class Foo:
|
|
58
61
|
|
|
59
62
|
def __init__(self):
|
|
@@ -138,6 +141,9 @@ class TeleApi:
|
|
|
138
141
|
def getFooBar(self, x, y):
|
|
139
142
|
return x - y
|
|
140
143
|
|
|
144
|
+
def genGetFooBar(self, x, y):
|
|
145
|
+
yield self.getFooBar(x, y)
|
|
146
|
+
|
|
141
147
|
async def customshare(self):
|
|
142
148
|
return await CustomShare.anit(self.link, 42)
|
|
143
149
|
|
|
@@ -160,6 +166,11 @@ class TeleAware(s_telepath.Aware):
|
|
|
160
166
|
|
|
161
167
|
return self._initBeep(path[0])
|
|
162
168
|
|
|
169
|
+
async def getTeleFeats(self):
|
|
170
|
+
return {
|
|
171
|
+
'aware': 1,
|
|
172
|
+
}
|
|
173
|
+
|
|
163
174
|
class TeleAuth(s_telepath.Aware):
|
|
164
175
|
|
|
165
176
|
def getTeleApi(self, link, mesg, path):
|
|
@@ -632,7 +643,15 @@ class TeleTest(s_t_utils.SynTest):
|
|
|
632
643
|
self.len(1, snfo)
|
|
633
644
|
self.eq(snfo[0].get('items'), {None: 'synapse.tests.test_telepath.TeleApi'})
|
|
634
645
|
|
|
646
|
+
self.true(proxy._hasTeleFeat('aware'))
|
|
647
|
+
self.false(proxy._hasTeleFeat('aware', vers=2))
|
|
648
|
+
self.false(proxy._hasTeleFeat('newp'))
|
|
649
|
+
|
|
650
|
+
self.true(proxy._hasTeleMeth('getFooBar'))
|
|
651
|
+
self.false(proxy._hasTeleMeth('getBarBaz'))
|
|
652
|
+
|
|
635
653
|
self.eq(10, await proxy.getFooBar(20, 10))
|
|
654
|
+
self.eq([10], [m async for m in await proxy.genGetFooBar(20, 10)])
|
|
636
655
|
|
|
637
656
|
# check a custom share works
|
|
638
657
|
obj = await proxy.customshare()
|
|
@@ -674,7 +693,14 @@ class TeleTest(s_t_utils.SynTest):
|
|
|
674
693
|
|
|
675
694
|
# check that a dynamic share works
|
|
676
695
|
async with await self.getTestProxy(dmon, 'woke/up') as proxy:
|
|
696
|
+
self.isin('synapse.tests.test_telepath.Beep', proxy._getClasses())
|
|
697
|
+
self.notin('synapse.tests.test_telepath.TeleApi', proxy._getClasses())
|
|
677
698
|
self.eq('up: beep', await proxy.beep())
|
|
699
|
+
self.eq(['up: beep'], [m async for m in await proxy.genbeep()])
|
|
700
|
+
# Telepath features are a function of the base object, not the result of getTeleApi
|
|
701
|
+
self.true(proxy._hasTeleFeat('aware'))
|
|
702
|
+
self.false(proxy._hasTeleFeat('aware', vers=2))
|
|
703
|
+
self.false(proxy._hasTeleFeat('newp'))
|
|
678
704
|
|
|
679
705
|
async def test_telepath_auth(self):
|
|
680
706
|
|
synapse/tests/test_tools_aha.py
CHANGED
|
@@ -3,14 +3,17 @@ import shutil
|
|
|
3
3
|
|
|
4
4
|
from unittest import mock
|
|
5
5
|
|
|
6
|
+
import synapse.exc as s_exc
|
|
6
7
|
import synapse.common as s_common
|
|
7
8
|
import synapse.lib.cell as s_cell
|
|
9
|
+
import synapse.lib.version as s_version
|
|
8
10
|
|
|
9
11
|
import synapse.tests.utils as s_t_utils
|
|
10
12
|
|
|
11
13
|
import synapse.tools.aha.list as s_a_list
|
|
12
14
|
import synapse.tools.aha.clone as s_a_clone
|
|
13
15
|
import synapse.tools.aha.enroll as s_a_enroll
|
|
16
|
+
import synapse.tools.aha.mirror as s_a_mirror
|
|
14
17
|
import synapse.tools.aha.easycert as s_a_easycert
|
|
15
18
|
import synapse.tools.aha.provision.user as s_a_provision_user
|
|
16
19
|
|
|
@@ -170,3 +173,192 @@ class AhaToolsTest(s_t_utils.SynTest):
|
|
|
170
173
|
|
|
171
174
|
teleyaml = s_common.yamlload(syndir, 'telepath.yaml')
|
|
172
175
|
self.eq(teleyaml.get('version'), 1)
|
|
176
|
+
|
|
177
|
+
async def test_aha_mirror(self):
|
|
178
|
+
|
|
179
|
+
async with self.getTestAha() as aha:
|
|
180
|
+
|
|
181
|
+
base_svcinfo = {
|
|
182
|
+
'iden': 'test_iden',
|
|
183
|
+
'leader': 'leader',
|
|
184
|
+
'urlinfo': {
|
|
185
|
+
'scheme': 'tcp',
|
|
186
|
+
'host': '127.0.0.1',
|
|
187
|
+
'port': 0,
|
|
188
|
+
'hostname': 'test.host'
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
conf_no_iden = {'aha:provision': await aha.addAhaSvcProv('no.iden')}
|
|
193
|
+
async with self.getTestCell(s_cell.Cell, conf=conf_no_iden) as cell_no_iden:
|
|
194
|
+
svcinfo = {k: v for k, v in base_svcinfo.items() if k != 'iden'}
|
|
195
|
+
await aha.addAhaSvc('no.iden', svcinfo)
|
|
196
|
+
|
|
197
|
+
argv = ['--url', aha.getLocalUrl()]
|
|
198
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
199
|
+
self.eq(retn, 0)
|
|
200
|
+
outp.expect('Service Mirror Groups:')
|
|
201
|
+
self.notin('no.iden', str(outp))
|
|
202
|
+
|
|
203
|
+
conf_no_host = {'aha:provision': await aha.addAhaSvcProv('no.host')}
|
|
204
|
+
async with self.getTestCell(s_cell.Cell, conf=conf_no_host) as cell_no_host:
|
|
205
|
+
svcinfo = dict(base_svcinfo)
|
|
206
|
+
svcinfo['urlinfo'] = {k: v for k, v in base_svcinfo['urlinfo'].items() if k != 'hostname'}
|
|
207
|
+
await aha.addAhaSvc('no.host', svcinfo)
|
|
208
|
+
|
|
209
|
+
argv = ['--url', aha.getLocalUrl()]
|
|
210
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
211
|
+
self.eq(retn, 0)
|
|
212
|
+
outp.expect('Service Mirror Groups:')
|
|
213
|
+
self.notin('no.host', str(outp))
|
|
214
|
+
|
|
215
|
+
conf_no_leader = {'aha:provision': await aha.addAhaSvcProv('no.leader')}
|
|
216
|
+
async with self.getTestCell(s_cell.Cell, conf=conf_no_leader) as cell_no_leader:
|
|
217
|
+
svcinfo = {k: v for k, v in base_svcinfo.items() if k != 'leader'}
|
|
218
|
+
await aha.addAhaSvc('no.leader', svcinfo)
|
|
219
|
+
|
|
220
|
+
argv = ['--url', aha.getLocalUrl()]
|
|
221
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
222
|
+
self.eq(retn, 0)
|
|
223
|
+
outp.expect('Service Mirror Groups:')
|
|
224
|
+
self.notin('no.leader', str(outp))
|
|
225
|
+
|
|
226
|
+
conf_no_primary = {'aha:provision': await aha.addAhaSvcProv('no.primary')}
|
|
227
|
+
async with self.getTestCell(s_cell.Cell, conf=conf_no_primary) as cell_no_primary:
|
|
228
|
+
svcinfo = dict(base_svcinfo)
|
|
229
|
+
svcinfo['urlinfo']['hostname'] = 'nonexistent.host'
|
|
230
|
+
await aha.addAhaSvc('no.primary', svcinfo)
|
|
231
|
+
|
|
232
|
+
async with aha.waiter(3, 'aha:svcadd', timeout=10):
|
|
233
|
+
|
|
234
|
+
conf = {'aha:provision': await aha.addAhaSvcProv('00.cell')}
|
|
235
|
+
cell00 = await aha.enter_context(self.getTestCell(conf=conf))
|
|
236
|
+
|
|
237
|
+
conf = {'aha:provision': await aha.addAhaSvcProv('01.cell', {'mirror': 'cell'})}
|
|
238
|
+
cell01 = await aha.enter_context(self.getTestCell(conf=conf))
|
|
239
|
+
|
|
240
|
+
await cell01.sync()
|
|
241
|
+
|
|
242
|
+
ahaurl = aha.getLocalUrl()
|
|
243
|
+
|
|
244
|
+
argv = ['--url', ahaurl]
|
|
245
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
246
|
+
self.eq(retn, 0)
|
|
247
|
+
outp.expect('Service Mirror Groups:')
|
|
248
|
+
outp.expect('00.cell.synapse')
|
|
249
|
+
outp.expect('01.cell.synapse')
|
|
250
|
+
outp.expect('Group Status: In Sync')
|
|
251
|
+
|
|
252
|
+
argv = ['--url', ahaurl, '--timeout', '30']
|
|
253
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
254
|
+
self.eq(retn, 0)
|
|
255
|
+
|
|
256
|
+
with mock.patch('synapse.telepath.Proxy._hasTeleFeat',
|
|
257
|
+
return_value=False):
|
|
258
|
+
argv = ['--url', ahaurl]
|
|
259
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
260
|
+
self.eq(retn, 1)
|
|
261
|
+
outp.expect(f'Service at {ahaurl} does not support the required callpeers feature.')
|
|
262
|
+
|
|
263
|
+
with mock.patch('synapse.telepath.Proxy._hasTeleFeat',
|
|
264
|
+
side_effect=s_exc.NoSuchMeth(name='_hasTeleFeat')):
|
|
265
|
+
argv = ['--url', ahaurl]
|
|
266
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
267
|
+
self.eq(retn, 1)
|
|
268
|
+
outp.expect(f'Service at {ahaurl} does not support the required callpeers feature.')
|
|
269
|
+
|
|
270
|
+
argv = ['--url', 'tcp://newp:1234/']
|
|
271
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
272
|
+
self.eq(retn, 1)
|
|
273
|
+
outp.expect('ERROR:')
|
|
274
|
+
|
|
275
|
+
async def mockCellInfo():
|
|
276
|
+
return {
|
|
277
|
+
'cell': {'ready': True, 'nexsindx': 10, 'uplink': None},
|
|
278
|
+
'synapse': {'verstring': s_version.verstring},
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async def mockOutOfSyncCellInfo():
|
|
282
|
+
return {
|
|
283
|
+
'cell': {'ready': True, 'nexsindx': 5, 'uplink': cell00.iden},
|
|
284
|
+
'synapse': {'verstring': s_version.verstring},
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
with mock.patch.object(cell00, 'getCellInfo', mockCellInfo):
|
|
288
|
+
with mock.patch.object(cell01, 'getCellInfo', mockOutOfSyncCellInfo):
|
|
289
|
+
async def mock_call_aha(*args, **kwargs):
|
|
290
|
+
todo = args[1]
|
|
291
|
+
if todo[0] == 'waitNexsOffs':
|
|
292
|
+
yield ('00.cell.synapse', (True, True))
|
|
293
|
+
yield ('01.cell.synapse', (True, True))
|
|
294
|
+
elif todo[0] == 'getCellInfo':
|
|
295
|
+
if not hasattr(mock_call_aha, 'called'):
|
|
296
|
+
mock_call_aha.called = True
|
|
297
|
+
yield ('00.cell.synapse', (True, await mockCellInfo()))
|
|
298
|
+
yield ('01.cell.synapse', (True, await mockOutOfSyncCellInfo()))
|
|
299
|
+
else:
|
|
300
|
+
yield ('00.cell.synapse', (True, await mockCellInfo()))
|
|
301
|
+
yield ('01.cell.synapse', (True, await mockCellInfo()))
|
|
302
|
+
|
|
303
|
+
with mock.patch.object(aha, 'callAhaPeerApi', mock_call_aha):
|
|
304
|
+
argv = ['--url', ahaurl, '--wait']
|
|
305
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
306
|
+
self.eq(retn, 0)
|
|
307
|
+
outp.expect('Group Status: Out of Sync')
|
|
308
|
+
outp.expect('Updated status:')
|
|
309
|
+
outp.expect('Group Status: In Sync')
|
|
310
|
+
|
|
311
|
+
with mock.patch.object(cell00, 'getCellInfo', mockCellInfo):
|
|
312
|
+
with mock.patch.object(cell01, 'getCellInfo', mockOutOfSyncCellInfo):
|
|
313
|
+
argv = ['--url', ahaurl, '--timeout', '1']
|
|
314
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
315
|
+
self.eq(retn, 0)
|
|
316
|
+
outp.expect('Group Status: Out of Sync')
|
|
317
|
+
|
|
318
|
+
async with self.getTestCore() as core:
|
|
319
|
+
curl = core.getLocalUrl()
|
|
320
|
+
argv = ['--url', curl]
|
|
321
|
+
with mock.patch('synapse.telepath.Proxy._hasTeleFeat',
|
|
322
|
+
return_value=True):
|
|
323
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
324
|
+
self.eq(1, retn)
|
|
325
|
+
outp.expect(f'Service at {curl} is not an Aha server')
|
|
326
|
+
|
|
327
|
+
async with aha.waiter(1, 'aha:svcadd', timeout=10):
|
|
328
|
+
|
|
329
|
+
conf = {'aha:provision': await aha.addAhaSvcProv('02.cell', {'mirror': 'cell'})}
|
|
330
|
+
cell02 = await aha.enter_context(self.getTestCell(conf=conf))
|
|
331
|
+
await cell02.sync()
|
|
332
|
+
|
|
333
|
+
async def mock_failed_api(*args, **kwargs):
|
|
334
|
+
yield ('00.cell.synapse', (True, {'cell': {'ready': True, 'nexsindx': 10}}))
|
|
335
|
+
yield ('01.cell.synapse', (False, 'error'))
|
|
336
|
+
yield ('02.cell.synapse', (True, {'cell': {'ready': True, 'nexsindx': 12}}))
|
|
337
|
+
|
|
338
|
+
with mock.patch.object(aha, 'callAhaPeerApi', mock_failed_api):
|
|
339
|
+
argv = ['--url', ahaurl, '--timeout', '1']
|
|
340
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
341
|
+
outp.expect('00.cell.synapse leader True True 127.0.0.1', whitespace=False)
|
|
342
|
+
outp.expect('nexsindx 10', whitespace=False)
|
|
343
|
+
outp.expect('02.cell.synapse leader True True 127.0.0.1', whitespace=False)
|
|
344
|
+
outp.expect('nexsindx 12', whitespace=False)
|
|
345
|
+
outp.expect('01.cell.synapse <unknown> True True', whitespace=False)
|
|
346
|
+
outp.expect('<unknown> <unknown>', whitespace=False)
|
|
347
|
+
|
|
348
|
+
self.eq(s_a_mirror.timeout_type('30'), 30)
|
|
349
|
+
self.eq(s_a_mirror.timeout_type('0'), 0)
|
|
350
|
+
|
|
351
|
+
with self.raises(s_exc.BadArg) as cm:
|
|
352
|
+
s_a_mirror.timeout_type('-1')
|
|
353
|
+
self.isin('is not a valid non-negative integer', cm.exception.get('mesg'))
|
|
354
|
+
|
|
355
|
+
with self.raises(s_exc.BadArg) as cm:
|
|
356
|
+
s_a_mirror.timeout_type('foo')
|
|
357
|
+
self.isin('is not a valid non-negative integer', cm.exception.get('mesg'))
|
|
358
|
+
|
|
359
|
+
synerr = s_exc.SynErr(mesg='Oof')
|
|
360
|
+
with mock.patch('synapse.telepath.openurl', side_effect=synerr):
|
|
361
|
+
argv = ['--url', 'tcp://test:1234/']
|
|
362
|
+
retn, outp = await self.execToolMain(s_a_mirror.main, argv)
|
|
363
|
+
self.eq(retn, 1)
|
|
364
|
+
outp.expect('ERROR: Oof')
|