synapse 2.195.1__py311-none-any.whl → 2.196.0__py311-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse might be problematic. Click here for more details.
- synapse/axon.py +72 -5
- synapse/common.py +23 -0
- synapse/cortex.py +1 -0
- synapse/daemon.py +1 -0
- synapse/lib/aha.py +159 -4
- synapse/lib/cell.py +133 -8
- synapse/lib/jsonstor.py +2 -1
- synapse/lib/modelrev.py +5 -1
- synapse/lib/nexus.py +4 -1
- synapse/lib/reflect.py +4 -5
- synapse/lib/snap.py +14 -7
- synapse/lib/stormlib/aha.py +351 -1
- synapse/lib/stormlib/utils.py +37 -0
- synapse/lib/stormtypes.py +118 -0
- synapse/lib/version.py +2 -2
- synapse/models/base.py +3 -0
- synapse/models/infotech.py +55 -16
- synapse/models/orgs.py +14 -10
- synapse/models/risk.py +23 -10
- synapse/models/transport.py +8 -3
- synapse/telepath.py +12 -0
- synapse/tests/test_axon.py +23 -0
- synapse/tests/test_common.py +28 -0
- synapse/tests/test_datamodel.py +8 -0
- synapse/tests/test_lib_aha.py +241 -0
- synapse/tests/test_lib_cell.py +61 -0
- synapse/tests/test_lib_jsonstor.py +1 -0
- synapse/tests/test_lib_modelrev.py +6 -0
- synapse/tests/test_lib_stormlib_aha.py +188 -0
- synapse/tests/test_lib_stormlib_utils.py +14 -0
- synapse/tests/test_lib_stormtypes.py +90 -3
- synapse/tests/test_model_base.py +2 -0
- synapse/tests/test_model_infotech.py +28 -1
- synapse/tests/test_model_orgs.py +2 -0
- synapse/tests/test_model_risk.py +2 -0
- synapse/tests/test_model_transport.py +1 -0
- synapse/tests/test_telepath.py +26 -0
- synapse/tests/test_tools_aha.py +192 -0
- synapse/tools/aha/mirror.py +193 -0
- synapse/tools/changelog.py +32 -27
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/METADATA +1 -1
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/RECORD +45 -42
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/LICENSE +0 -0
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/WHEEL +0 -0
- {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/top_level.txt +0 -0
synapse/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')
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import asyncio
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
import synapse.exc as s_exc
|
|
6
|
+
import synapse.common as s_common
|
|
7
|
+
import synapse.telepath as s_telepath
|
|
8
|
+
|
|
9
|
+
import synapse.lib.output as s_output
|
|
10
|
+
import synapse.lib.version as s_version
|
|
11
|
+
|
|
12
|
+
descr = '''
|
|
13
|
+
Query the Aha server for the service cluster status of mirrors.
|
|
14
|
+
|
|
15
|
+
Examples:
|
|
16
|
+
|
|
17
|
+
python -m synapse.tools.aha.mirror --timeout 30
|
|
18
|
+
|
|
19
|
+
'''
|
|
20
|
+
|
|
21
|
+
async def get_cell_infos(prox, iden, members, timeout):
|
|
22
|
+
cell_infos = {}
|
|
23
|
+
if iden is not None:
|
|
24
|
+
todo = s_common.todo('getCellInfo')
|
|
25
|
+
async for svcname, (ok, info) in prox.callAhaPeerApi(iden, todo, timeout=timeout):
|
|
26
|
+
if not ok:
|
|
27
|
+
continue
|
|
28
|
+
cell_infos[svcname] = info
|
|
29
|
+
return cell_infos
|
|
30
|
+
|
|
31
|
+
def build_status_list(members, cell_infos):
|
|
32
|
+
group_status = []
|
|
33
|
+
for svc in members:
|
|
34
|
+
svcname = svc.get('name')
|
|
35
|
+
svcinfo = svc.get('svcinfo', {})
|
|
36
|
+
status = {
|
|
37
|
+
'name': svcname,
|
|
38
|
+
'role': '<unknown>',
|
|
39
|
+
'online': str('online' in svcinfo),
|
|
40
|
+
'ready': 'True',
|
|
41
|
+
'host': svcinfo.get('urlinfo', {}).get('host', ''),
|
|
42
|
+
'port': str(svcinfo.get('urlinfo', {}).get('port', '')),
|
|
43
|
+
'version': '<unknown>',
|
|
44
|
+
'nexs_indx': 0
|
|
45
|
+
}
|
|
46
|
+
if svcname in cell_infos:
|
|
47
|
+
info = cell_infos[svcname]
|
|
48
|
+
cell_info = info.get('cell', {})
|
|
49
|
+
status.update({
|
|
50
|
+
'nexs_indx': cell_info.get('nexsindx', 0),
|
|
51
|
+
'role': 'follower' if cell_info.get('uplink') else 'leader',
|
|
52
|
+
'version': str(info.get('synapse', {}).get('verstring', '')),
|
|
53
|
+
'online': 'True',
|
|
54
|
+
'ready': str(cell_info.get('ready', False))
|
|
55
|
+
})
|
|
56
|
+
group_status.append(status)
|
|
57
|
+
return group_status
|
|
58
|
+
|
|
59
|
+
def output_status(outp, vname, group_status):
|
|
60
|
+
header = ' {:<40} {:<10} {:<8} {:<7} {:<16} {:<9} {:<12} {:<10}'.format(
|
|
61
|
+
'name', 'role', 'online', 'ready', 'host', 'port', 'version', 'nexus idx')
|
|
62
|
+
outp.printf(header)
|
|
63
|
+
outp.printf('#' * 120)
|
|
64
|
+
outp.printf(vname)
|
|
65
|
+
for status in group_status:
|
|
66
|
+
if status['nexs_indx'] == 0:
|
|
67
|
+
status['nexs_indx'] = '<unknown>'
|
|
68
|
+
line = ' {name:<40} {role:<10} {online:<8} {ready:<7} {host:<16} {port:<9} {version:<12} {nexs_indx:<10}'.format(**status)
|
|
69
|
+
outp.printf(line)
|
|
70
|
+
|
|
71
|
+
def check_sync_status(group_status):
|
|
72
|
+
indices = {status['nexs_indx'] for status in group_status}
|
|
73
|
+
known_count = sum(1 for status in group_status)
|
|
74
|
+
return len(indices) == 1 and known_count == len(group_status)
|
|
75
|
+
|
|
76
|
+
def timeout_type(valu):
|
|
77
|
+
try:
|
|
78
|
+
ivalu = int(valu)
|
|
79
|
+
if ivalu < 0:
|
|
80
|
+
raise ValueError
|
|
81
|
+
except ValueError:
|
|
82
|
+
raise s_exc.BadArg(mesg=f"{valu} is not a valid non-negative integer")
|
|
83
|
+
return ivalu
|
|
84
|
+
|
|
85
|
+
async def main(argv, outp=s_output.stdout):
|
|
86
|
+
|
|
87
|
+
pars = argparse.ArgumentParser(prog='synapse.tools.aha.mirror', description=descr,
|
|
88
|
+
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
89
|
+
|
|
90
|
+
pars.add_argument('--url', default='cell:///vertex/storage', help='The telepath URL to connect to the AHA service.')
|
|
91
|
+
pars.add_argument('--timeout', type=timeout_type, default=10, help='The timeout in seconds for individual service API calls')
|
|
92
|
+
pars.add_argument('--wait', action='store_true', help='Whether to wait for the mirrors to sync.')
|
|
93
|
+
opts = pars.parse_args(argv)
|
|
94
|
+
|
|
95
|
+
async with s_telepath.withTeleEnv():
|
|
96
|
+
try:
|
|
97
|
+
async with await s_telepath.openurl(opts.url) as prox:
|
|
98
|
+
try:
|
|
99
|
+
if not prox._hasTeleFeat('callpeers', vers=1):
|
|
100
|
+
outp.printf(f'Service at {opts.url} does not support the required callpeers feature.')
|
|
101
|
+
return 1
|
|
102
|
+
except s_exc.NoSuchMeth:
|
|
103
|
+
outp.printf(f'Service at {opts.url} does not support the required callpeers feature.')
|
|
104
|
+
return 1
|
|
105
|
+
classes = prox._getClasses()
|
|
106
|
+
if 'synapse.lib.aha.AhaApi' not in classes:
|
|
107
|
+
outp.printf(f'Service at {opts.url} is not an Aha server')
|
|
108
|
+
return 1
|
|
109
|
+
|
|
110
|
+
virtual_services, member_servers = {}, {}
|
|
111
|
+
async for svc in prox.getAhaSvcs():
|
|
112
|
+
name = svc.get('name', '')
|
|
113
|
+
svcinfo = svc.get('svcinfo', {})
|
|
114
|
+
urlinfo = svcinfo.get('urlinfo', {})
|
|
115
|
+
hostname = urlinfo.get('hostname', '')
|
|
116
|
+
|
|
117
|
+
if name != hostname:
|
|
118
|
+
virtual_services[name] = svc
|
|
119
|
+
else:
|
|
120
|
+
member_servers[name] = svc
|
|
121
|
+
|
|
122
|
+
mirror_groups = {}
|
|
123
|
+
for vname, vsvc in virtual_services.items():
|
|
124
|
+
vsvc_info = vsvc.get('svcinfo', {})
|
|
125
|
+
vsvc_iden = vsvc_info.get('iden')
|
|
126
|
+
vsvc_leader = vsvc_info.get('leader')
|
|
127
|
+
vsvc_hostname = vsvc_info.get('urlinfo', {}).get('hostname', '')
|
|
128
|
+
|
|
129
|
+
if not vsvc_iden or not vsvc_hostname or not vsvc_leader:
|
|
130
|
+
continue
|
|
131
|
+
|
|
132
|
+
primary_member = member_servers.get(vsvc_hostname)
|
|
133
|
+
if not primary_member:
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
members = [primary_member] + [
|
|
137
|
+
msvc for mname, msvc in member_servers.items()
|
|
138
|
+
if mname != vsvc_hostname and
|
|
139
|
+
msvc.get('svcinfo', {}).get('iden') == vsvc_iden and
|
|
140
|
+
msvc.get('svcinfo', {}).get('leader') == vsvc_leader
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
if len(members) > 1:
|
|
144
|
+
mirror_groups[vname] = members
|
|
145
|
+
|
|
146
|
+
outp.printf('Service Mirror Groups:')
|
|
147
|
+
for vname, members in mirror_groups.items():
|
|
148
|
+
iden = members[0].get('svcinfo', {}).get('iden')
|
|
149
|
+
|
|
150
|
+
cell_infos = await get_cell_infos(prox, iden, members, opts.timeout)
|
|
151
|
+
group_status = build_status_list(members, cell_infos)
|
|
152
|
+
output_status(outp, vname, group_status)
|
|
153
|
+
|
|
154
|
+
if check_sync_status(group_status):
|
|
155
|
+
outp.printf('Group Status: In Sync')
|
|
156
|
+
else:
|
|
157
|
+
outp.printf(f'Group Status: Out of Sync')
|
|
158
|
+
if opts.wait:
|
|
159
|
+
leader_nexs = None
|
|
160
|
+
for status in group_status:
|
|
161
|
+
if status['role'] == 'leader' and isinstance(status['nexs_indx'], int):
|
|
162
|
+
leader_nexs = status['nexs_indx']
|
|
163
|
+
|
|
164
|
+
if leader_nexs is not None:
|
|
165
|
+
while True:
|
|
166
|
+
responses = []
|
|
167
|
+
todo = s_common.todo('waitNexsOffs', leader_nexs - 1, timeout=opts.timeout)
|
|
168
|
+
async for svcname, (ok, info) in prox.callAhaPeerApi(iden, todo, timeout=opts.timeout):
|
|
169
|
+
if ok and info:
|
|
170
|
+
responses.append((svcname, info))
|
|
171
|
+
|
|
172
|
+
if len(responses) == len(members):
|
|
173
|
+
cell_infos = await get_cell_infos(prox, iden, members, opts.timeout)
|
|
174
|
+
group_status = build_status_list(members, cell_infos)
|
|
175
|
+
|
|
176
|
+
outp.printf('\nUpdated status:')
|
|
177
|
+
output_status(outp, vname, group_status)
|
|
178
|
+
|
|
179
|
+
if check_sync_status(group_status):
|
|
180
|
+
outp.printf('Group Status: In Sync')
|
|
181
|
+
break
|
|
182
|
+
|
|
183
|
+
return 0
|
|
184
|
+
|
|
185
|
+
except Exception as e:
|
|
186
|
+
mesg = repr(e)
|
|
187
|
+
if isinstance(e, s_exc.SynErr):
|
|
188
|
+
mesg = e.errinfo.get('mesg', repr(e))
|
|
189
|
+
outp.printf(f'ERROR: {mesg}')
|
|
190
|
+
return 1
|
|
191
|
+
|
|
192
|
+
if __name__ == '__main__': # pragma: no cover
|
|
193
|
+
sys.exit(asyncio.run(main(sys.argv[1:])))
|
synapse/tools/changelog.py
CHANGED
|
@@ -886,34 +886,8 @@ async def format(opts: argparse.Namespace,
|
|
|
886
886
|
modeldiff = False
|
|
887
887
|
clean_vers_ref = opts.version.replace(".", "_")
|
|
888
888
|
model_rst_ref = f'userguide_model_{clean_vers_ref}'
|
|
889
|
-
for key, header in s_schemas._changelogTypes.items():
|
|
890
|
-
dataz = entries.get(key)
|
|
891
|
-
if dataz:
|
|
892
|
-
text = text + f'\n{header}\n{"-" * len(header)}'
|
|
893
|
-
dataz.sort(key=lambda x: x.get('prs'))
|
|
894
|
-
for data in dataz:
|
|
895
|
-
desc = data.get('desc') # type: str
|
|
896
|
-
desc_lines = desc.splitlines()
|
|
897
|
-
for i, chunk in enumerate(desc_lines):
|
|
898
|
-
if i == 0:
|
|
899
|
-
for line in textwrap.wrap(chunk, initial_indent='- ', subsequent_indent=' ', width=opts.width):
|
|
900
|
-
text = f'{text}\n{line}'
|
|
901
|
-
else:
|
|
902
|
-
text = text + '\n'
|
|
903
|
-
for line in textwrap.wrap(chunk, initial_indent=' ', subsequent_indent=' ', width=opts.width):
|
|
904
|
-
text = f'{text}\n{line}'
|
|
905
|
-
|
|
906
|
-
if not opts.hide_prs:
|
|
907
|
-
for pr in data.get('prs'):
|
|
908
|
-
text = f'{text}\n (`#{pr} <https://github.com/vertexproject/synapse/pull/{pr}>`_)'
|
|
909
|
-
if key == 'migration':
|
|
910
|
-
text = text + '\n- See :ref:`datamigration` for more information about automatic migrations.'
|
|
911
|
-
elif key == 'model':
|
|
912
|
-
text = text + f'\n- See :ref:`{model_rst_ref}` for more detailed model changes.'
|
|
913
|
-
modeldiff = True
|
|
914
|
-
text = text + '\n'
|
|
915
889
|
|
|
916
|
-
if
|
|
890
|
+
if opts.model_ref:
|
|
917
891
|
# TODO find previous model file automatically?
|
|
918
892
|
if opts.verbose:
|
|
919
893
|
outp.printf(f'Getting reference model from {opts.model_ref}')
|
|
@@ -934,6 +908,8 @@ async def format(opts: argparse.Namespace,
|
|
|
934
908
|
changes = differ.diffModl(outp)
|
|
935
909
|
has_changes = sum([len(v) for v in changes.values()])
|
|
936
910
|
if has_changes:
|
|
911
|
+
entries['model'].append({'prs': [], 'type': 'skip'})
|
|
912
|
+
modeldiff = True
|
|
937
913
|
rst = _gen_model_rst(opts.version, model_rst_ref, changes, cur_modl, outp, width=opts.width)
|
|
938
914
|
model_text = rst.getRstText()
|
|
939
915
|
if opts.verbose:
|
|
@@ -955,6 +931,35 @@ async def format(opts: argparse.Namespace,
|
|
|
955
931
|
else:
|
|
956
932
|
outp.printf(f'No model changes detected.')
|
|
957
933
|
|
|
934
|
+
for key, header in s_schemas._changelogTypes.items():
|
|
935
|
+
dataz = entries.get(key)
|
|
936
|
+
if dataz:
|
|
937
|
+
text = text + f'\n{header}\n{"-" * len(header)}'
|
|
938
|
+
dataz.sort(key=lambda x: x.get('prs'))
|
|
939
|
+
for data in dataz:
|
|
940
|
+
desc = data.get('desc') # type: str
|
|
941
|
+
if desc is None and data.get('type') == 'skip':
|
|
942
|
+
continue
|
|
943
|
+
desc_lines = desc.splitlines()
|
|
944
|
+
for i, chunk in enumerate(desc_lines):
|
|
945
|
+
if i == 0:
|
|
946
|
+
for line in textwrap.wrap(chunk, initial_indent='- ', subsequent_indent=' ', width=opts.width):
|
|
947
|
+
text = f'{text}\n{line}'
|
|
948
|
+
else:
|
|
949
|
+
text = text + '\n'
|
|
950
|
+
for line in textwrap.wrap(chunk, initial_indent=' ', subsequent_indent=' ', width=opts.width):
|
|
951
|
+
text = f'{text}\n{line}'
|
|
952
|
+
|
|
953
|
+
if not opts.hide_prs:
|
|
954
|
+
for pr in data.get('prs'):
|
|
955
|
+
text = f'{text}\n (`#{pr} <https://github.com/vertexproject/synapse/pull/{pr}>`_)'
|
|
956
|
+
if key == 'migration':
|
|
957
|
+
text = text + '\n- See :ref:`datamigration` for more information about automatic migrations.'
|
|
958
|
+
elif key == 'model':
|
|
959
|
+
if modeldiff:
|
|
960
|
+
text = text + f'\n- See :ref:`{model_rst_ref}` for more detailed model changes.'
|
|
961
|
+
text = text + '\n'
|
|
962
|
+
|
|
958
963
|
if opts.rm:
|
|
959
964
|
if opts.verbose:
|
|
960
965
|
outp.printf('Staging file removals in git')
|