synapse 2.195.1__py311-none-any.whl → 2.197.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (60) hide show
  1. synapse/axon.py +72 -5
  2. synapse/common.py +23 -0
  3. synapse/cortex.py +13 -8
  4. synapse/cryotank.py +2 -2
  5. synapse/daemon.py +1 -0
  6. synapse/lib/aha.py +159 -4
  7. synapse/lib/cell.py +133 -8
  8. synapse/lib/config.py +3 -3
  9. synapse/lib/jsonstor.py +2 -1
  10. synapse/lib/modelrev.py +5 -1
  11. synapse/lib/multislabseqn.py +2 -2
  12. synapse/lib/nexus.py +4 -1
  13. synapse/lib/reflect.py +4 -5
  14. synapse/lib/schemas.py +478 -1
  15. synapse/lib/snap.py +14 -7
  16. synapse/lib/storm.py +12 -394
  17. synapse/lib/stormlib/aha.py +351 -1
  18. synapse/lib/stormlib/graph.py +0 -61
  19. synapse/lib/stormlib/index.py +52 -0
  20. synapse/lib/stormlib/utils.py +37 -0
  21. synapse/lib/stormtypes.py +121 -1
  22. synapse/lib/task.py +13 -2
  23. synapse/lib/urlhelp.py +1 -1
  24. synapse/lib/version.py +2 -2
  25. synapse/models/base.py +3 -0
  26. synapse/models/doc.py +62 -0
  27. synapse/models/infotech.py +55 -16
  28. synapse/models/orgs.py +20 -14
  29. synapse/models/risk.py +23 -10
  30. synapse/models/transport.py +8 -3
  31. synapse/telepath.py +12 -0
  32. synapse/tests/test_axon.py +23 -0
  33. synapse/tests/test_common.py +28 -0
  34. synapse/tests/test_datamodel.py +15 -0
  35. synapse/tests/test_lib_aha.py +201 -0
  36. synapse/tests/test_lib_boss.py +15 -6
  37. synapse/tests/test_lib_cell.py +104 -0
  38. synapse/tests/test_lib_jsonstor.py +1 -0
  39. synapse/tests/test_lib_modelrev.py +6 -0
  40. synapse/tests/test_lib_stormlib_aha.py +188 -0
  41. synapse/tests/test_lib_stormlib_index.py +39 -0
  42. synapse/tests/test_lib_stormlib_utils.py +14 -0
  43. synapse/tests/test_lib_stormtypes.py +90 -3
  44. synapse/tests/test_lib_task.py +31 -13
  45. synapse/tests/test_model_base.py +2 -0
  46. synapse/tests/test_model_doc.py +38 -0
  47. synapse/tests/test_model_infotech.py +28 -1
  48. synapse/tests/test_model_orgs.py +9 -0
  49. synapse/tests/test_model_risk.py +2 -0
  50. synapse/tests/test_model_transport.py +1 -0
  51. synapse/tests/test_telepath.py +26 -0
  52. synapse/tests/test_tools_aha.py +192 -0
  53. synapse/tools/aha/mirror.py +193 -0
  54. synapse/tools/changelog.py +32 -27
  55. synapse/tools/genpkg.py +2 -2
  56. {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/METADATA +1 -1
  57. {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/RECORD +60 -55
  58. {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/LICENSE +0 -0
  59. {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/WHEEL +0 -0
  60. {synapse-2.195.1.dist-info → synapse-2.197.0.dist-info}/top_level.txt +0 -0
@@ -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
 
@@ -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:])))
@@ -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 modeldiff and opts.model_ref:
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')
synapse/tools/genpkg.py CHANGED
@@ -12,10 +12,10 @@ import synapse.exc as s_exc
12
12
  import synapse.common as s_common
13
13
  import synapse.telepath as s_telepath
14
14
 
15
- import synapse.lib.storm as s_storm
16
15
  import synapse.lib.output as s_output
17
16
  import synapse.lib.certdir as s_certdir
18
17
  import synapse.lib.dyndeps as s_dyndeps
18
+ import synapse.lib.schemas as s_schemas
19
19
 
20
20
  logger = logging.getLogger(__name__)
21
21
 
@@ -221,7 +221,7 @@ def loadPkgProto(path, opticdir=None, no_docs=False, readonly=False):
221
221
  pkgdef['optic'].setdefault('files', {})
222
222
  loadOpticFiles(pkgdef, opticdir)
223
223
 
224
- s_storm.reqValidPkgdef(pkgdef)
224
+ s_schemas.reqValidPkgdef(pkgdef)
225
225
 
226
226
  # Ensure the package is json safe and tuplify it.
227
227
  s_common.reqJsonSafeStrict(pkgdef)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: synapse
3
- Version: 2.195.1
3
+ Version: 2.197.0
4
4
  Summary: Synapse Intelligence Analysis Framework
5
5
  Author-email: The Vertex Project LLC <root@vertex.link>
6
6
  License: Apache License 2.0