synapse 2.176.0__py311-none-any.whl → 2.178.0__py311-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse might be problematic. Click here for more details.
- synapse/axon.py +24 -9
- synapse/cortex.py +337 -172
- synapse/cryotank.py +46 -37
- synapse/datamodel.py +17 -4
- synapse/exc.py +19 -0
- synapse/lib/agenda.py +7 -13
- synapse/lib/aha.py +361 -88
- synapse/lib/auth.py +1520 -0
- synapse/lib/base.py +27 -9
- synapse/lib/cell.py +422 -163
- synapse/lib/config.py +15 -11
- synapse/lib/coro.py +13 -0
- synapse/lib/grammar.py +5 -0
- synapse/lib/hive.py +24 -3
- synapse/lib/hiveauth.py +6 -32
- synapse/lib/layer.py +7 -9
- synapse/lib/link.py +22 -18
- synapse/lib/lmdbslab.py +152 -3
- synapse/lib/modelrev.py +1 -1
- synapse/lib/nexus.py +24 -12
- synapse/lib/schemas.py +136 -0
- synapse/lib/storm.py +61 -29
- synapse/lib/stormlib/aha.py +1 -1
- synapse/lib/stormlib/auth.py +185 -10
- synapse/lib/stormlib/cortex.py +16 -5
- synapse/lib/stormlib/gen.py +80 -0
- synapse/lib/stormlib/imap.py +6 -2
- synapse/lib/stormlib/model.py +55 -0
- synapse/lib/stormlib/modelext.py +60 -0
- synapse/lib/stormlib/smtp.py +12 -2
- synapse/lib/stormlib/tabular.py +212 -0
- synapse/lib/stormtypes.py +14 -1
- synapse/lib/trigger.py +1 -1
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +55 -28
- synapse/models/base.py +7 -0
- synapse/models/biz.py +4 -0
- synapse/models/files.py +8 -1
- synapse/models/inet.py +8 -0
- synapse/telepath.py +32 -17
- synapse/tests/files/aha/certs/cas/synapse.crt +28 -0
- synapse/tests/files/aha/certs/cas/synapse.key +51 -0
- synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.crt +30 -0
- synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.key +51 -0
- synapse/tests/files/aha/certs/users/root@synapse.crt +29 -0
- synapse/tests/files/aha/certs/users/root@synapse.key +51 -0
- synapse/tests/files/changelog/model_2.176.0_16ee721a6b7221344eaf946c3ab4602dda546b1a.yaml.gz +0 -0
- synapse/tests/files/changelog/model_2.176.0_2a25c58bbd344716cd7cbc3f4304d8925b0f4ef2.yaml.gz +0 -0
- synapse/tests/files/rstorm/testsvc.py +1 -1
- synapse/tests/test_axon.py +8 -5
- synapse/tests/test_cortex.py +149 -141
- synapse/tests/test_cryotank.py +4 -4
- synapse/tests/test_datamodel.py +7 -0
- synapse/tests/test_lib_agenda.py +10 -3
- synapse/tests/test_lib_aha.py +336 -490
- synapse/tests/{test_lib_hiveauth.py → test_lib_auth.py} +314 -11
- synapse/tests/test_lib_base.py +20 -0
- synapse/tests/test_lib_cell.py +210 -30
- synapse/tests/test_lib_config.py +4 -3
- synapse/tests/test_lib_httpapi.py +18 -14
- synapse/tests/test_lib_layer.py +33 -33
- synapse/tests/test_lib_link.py +42 -1
- synapse/tests/test_lib_lmdbslab.py +68 -0
- synapse/tests/test_lib_nexus.py +12 -4
- synapse/tests/test_lib_node.py +0 -7
- synapse/tests/test_lib_storm.py +45 -0
- synapse/tests/test_lib_stormlib_aha.py +35 -36
- synapse/tests/test_lib_stormlib_auth.py +21 -0
- synapse/tests/test_lib_stormlib_cell.py +4 -15
- synapse/tests/test_lib_stormlib_cortex.py +12 -12
- synapse/tests/test_lib_stormlib_gen.py +99 -0
- synapse/tests/test_lib_stormlib_imap.py +14 -3
- synapse/tests/test_lib_stormlib_model.py +108 -0
- synapse/tests/test_lib_stormlib_modelext.py +64 -0
- synapse/tests/test_lib_stormlib_smtp.py +51 -0
- synapse/tests/test_lib_stormlib_tabular.py +226 -0
- synapse/tests/test_lib_stormsvc.py +4 -1
- synapse/tests/test_lib_stormtypes.py +10 -0
- synapse/tests/test_model_base.py +3 -0
- synapse/tests/test_model_biz.py +3 -0
- synapse/tests/test_model_files.py +12 -2
- synapse/tests/test_model_inet.py +24 -0
- synapse/tests/test_tools_aha.py +78 -101
- synapse/tests/test_tools_changelog.py +196 -0
- synapse/tests/test_tools_healthcheck.py +4 -3
- synapse/tests/utils.py +87 -121
- synapse/tools/aha/clone.py +50 -0
- synapse/tools/aha/enroll.py +2 -1
- synapse/tools/backup.py +2 -2
- synapse/tools/changelog.py +776 -15
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/METADATA +48 -48
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/RECORD +95 -82
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/WHEEL +1 -1
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/LICENSE +0 -0
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/top_level.txt +0 -0
synapse/lib/nexus.py
CHANGED
|
@@ -91,7 +91,6 @@ class NexsRoot(s_base.Base):
|
|
|
91
91
|
self.writeholds = set()
|
|
92
92
|
|
|
93
93
|
self.applytask = None
|
|
94
|
-
self.applylock = asyncio.Lock()
|
|
95
94
|
|
|
96
95
|
self.ready = asyncio.Event()
|
|
97
96
|
self.donexslog = self.cell.conf.get('nexslog:en')
|
|
@@ -110,9 +109,7 @@ class NexsRoot(s_base.Base):
|
|
|
110
109
|
|
|
111
110
|
logpath = s_common.genpath(self.dirn, 'slabs', 'nexuslog')
|
|
112
111
|
|
|
113
|
-
self.
|
|
114
|
-
self.nexsslab = await s_lmdbslab.Slab.anit(path, map_async=self.map_async)
|
|
115
|
-
self.nexsslab.addResizeCallback(cell.checkFreeSpace)
|
|
112
|
+
self.nexsslab = await cell._initSlabFile(path)
|
|
116
113
|
|
|
117
114
|
self.nexshot = await self.nexsslab.getHotCount('nexs:indx')
|
|
118
115
|
|
|
@@ -126,8 +123,7 @@ class NexsRoot(s_base.Base):
|
|
|
126
123
|
elif vers != 2:
|
|
127
124
|
raise s_exc.BadStorageVersion(mesg=f'Got nexus log version {vers}. Expected 2. Accidental downgrade?')
|
|
128
125
|
|
|
129
|
-
|
|
130
|
-
self.nexslog = await s_multislabseqn.MultiSlabSeqn.anit(logpath, slabopts=slabopts, cell=cell)
|
|
126
|
+
self.nexslog = await s_multislabseqn.MultiSlabSeqn.anit(logpath, cell=cell)
|
|
131
127
|
|
|
132
128
|
# just in case were previously configured differently
|
|
133
129
|
logindx = self.nexslog.index()
|
|
@@ -147,6 +143,9 @@ class NexsRoot(s_base.Base):
|
|
|
147
143
|
|
|
148
144
|
self.onfini(fini)
|
|
149
145
|
|
|
146
|
+
def getNexsKids(self):
|
|
147
|
+
return list(self._nexskids.values())
|
|
148
|
+
|
|
150
149
|
async def _migrateV1toV2(self, nexspath, logpath):
|
|
151
150
|
'''
|
|
152
151
|
Close the slab, move it to the new multislab location, then copy out the nexshot
|
|
@@ -195,8 +194,7 @@ class NexsRoot(s_base.Base):
|
|
|
195
194
|
|
|
196
195
|
# Open a fresh slab where the old one used to be
|
|
197
196
|
logger.warning(f'Re-opening fresh nexslog slab at {nexspath} for nexshot')
|
|
198
|
-
self.nexsslab = await
|
|
199
|
-
self.nexsslab.addResizeCallback(self.cell.checkFreeSpace)
|
|
197
|
+
self.nexsslab = await self.cell._initSlabFile(nexspath)
|
|
200
198
|
|
|
201
199
|
self.nexshot = await self.nexsslab.getHotCount('nexs:indx')
|
|
202
200
|
|
|
@@ -230,7 +228,7 @@ class NexsRoot(s_base.Base):
|
|
|
230
228
|
|
|
231
229
|
async def enNexsLog(self):
|
|
232
230
|
|
|
233
|
-
async with self.
|
|
231
|
+
async with self.cell.nexslock:
|
|
234
232
|
|
|
235
233
|
if self.donexslog:
|
|
236
234
|
return
|
|
@@ -309,7 +307,6 @@ class NexsRoot(s_base.Base):
|
|
|
309
307
|
If I'm not a follower, mutate, otherwise, ask the leader to make the change and wait for the follower loop
|
|
310
308
|
to hand me the result through a future.
|
|
311
309
|
'''
|
|
312
|
-
|
|
313
310
|
# pick up a reference to avoid race when we eventually can promote
|
|
314
311
|
client = self.client
|
|
315
312
|
|
|
@@ -344,7 +341,7 @@ class NexsRoot(s_base.Base):
|
|
|
344
341
|
if meta is None:
|
|
345
342
|
meta = {}
|
|
346
343
|
|
|
347
|
-
async with self.
|
|
344
|
+
async with self.cell.nexslock:
|
|
348
345
|
self.reqNotReadOnly()
|
|
349
346
|
# Keep a reference to the shielded task to ensure it isn't GC'd
|
|
350
347
|
self.applytask = asyncio.create_task(self._eat((nexsiden, event, args, kwargs, meta)))
|
|
@@ -577,6 +574,9 @@ class NexsRoot(s_base.Base):
|
|
|
577
574
|
if respfutu is not None:
|
|
578
575
|
respfutu.set_result(retn)
|
|
579
576
|
|
|
577
|
+
except s_exc.LinkShutDown:
|
|
578
|
+
logger.warning(f'mirror loop: leader closed the connection.')
|
|
579
|
+
|
|
580
580
|
except Exception as exc: # pragma: no cover
|
|
581
581
|
logger.exception(f'error in mirror loop: {exc}')
|
|
582
582
|
|
|
@@ -634,9 +634,21 @@ class Pusher(s_base.Base, metaclass=RegMethType):
|
|
|
634
634
|
assert prev is not None, f'Failed removing {self.nexsiden}'
|
|
635
635
|
|
|
636
636
|
self.onfini(onfini)
|
|
637
|
-
|
|
638
637
|
self.nexsroot = nexsroot
|
|
639
638
|
|
|
639
|
+
async def modNexsRoot(self, ctor):
|
|
640
|
+
|
|
641
|
+
kids = [self]
|
|
642
|
+
if self.nexsroot is not None:
|
|
643
|
+
kids = self.nexsroot.getNexsKids()
|
|
644
|
+
await self.nexsroot.fini()
|
|
645
|
+
|
|
646
|
+
nexsroot = await ctor()
|
|
647
|
+
|
|
648
|
+
[kid.setNexsRoot(nexsroot) for kid in kids]
|
|
649
|
+
|
|
650
|
+
await nexsroot.startup()
|
|
651
|
+
|
|
640
652
|
@classmethod
|
|
641
653
|
def onPush(cls, event: str, passitem=False) -> Callable:
|
|
642
654
|
'''
|
synapse/lib/schemas.py
CHANGED
|
@@ -288,6 +288,93 @@ _stormPoolOptsSchema = {
|
|
|
288
288
|
}
|
|
289
289
|
reqValidStormPoolOpts = s_config.getJsValidator(_stormPoolOptsSchema)
|
|
290
290
|
|
|
291
|
+
_authRulesSchema = {
|
|
292
|
+
'type': 'array',
|
|
293
|
+
'items': {
|
|
294
|
+
'type': 'array',
|
|
295
|
+
'items': [
|
|
296
|
+
{'type': 'boolean'},
|
|
297
|
+
{'type': 'array', 'items': {'type': 'string'}},
|
|
298
|
+
],
|
|
299
|
+
'minItems': 2,
|
|
300
|
+
'maxItems': 2,
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
reqValidRules = s_config.getJsValidator(_authRulesSchema)
|
|
304
|
+
|
|
305
|
+
_passwdPolicySchema = {
|
|
306
|
+
'type': 'object',
|
|
307
|
+
'properties': {
|
|
308
|
+
'complexity': {
|
|
309
|
+
'type': ['object', 'null'],
|
|
310
|
+
'properties': {
|
|
311
|
+
'length': {
|
|
312
|
+
'type': ['number', 'null'],
|
|
313
|
+
'minimum': 1,
|
|
314
|
+
'description': 'Minimum password character length.',
|
|
315
|
+
},
|
|
316
|
+
'sequences': {
|
|
317
|
+
'type': ['number', 'null'],
|
|
318
|
+
'minimum': 2,
|
|
319
|
+
'description': 'Maximum sequence length in a password. Sequences can be letters or number, forward or reverse.',
|
|
320
|
+
},
|
|
321
|
+
'upper:count': {
|
|
322
|
+
'type': ['number', 'null'],
|
|
323
|
+
'description': 'The minimum number of uppercase characters required in password.',
|
|
324
|
+
},
|
|
325
|
+
'upper:valid': {
|
|
326
|
+
'type': ['string', 'null'],
|
|
327
|
+
'minLength': 1,
|
|
328
|
+
'description': 'All valid uppercase characters.',
|
|
329
|
+
},
|
|
330
|
+
'lower:count': {
|
|
331
|
+
'type': ['number', 'null'],
|
|
332
|
+
'minimum': 0,
|
|
333
|
+
'description': 'The minimum number of lowercase characters required in password.',
|
|
334
|
+
},
|
|
335
|
+
'lower:valid': {
|
|
336
|
+
'type': ['string', 'null'],
|
|
337
|
+
'minLength': 1,
|
|
338
|
+
'description': 'All valid lowercase characters.',
|
|
339
|
+
},
|
|
340
|
+
'special:count': {
|
|
341
|
+
'type': ['number', 'null'],
|
|
342
|
+
'minimum': 0,
|
|
343
|
+
'description': 'The minimum number of special characters required in password.',
|
|
344
|
+
},
|
|
345
|
+
'special:valid': {
|
|
346
|
+
'type': ['string', 'null'],
|
|
347
|
+
'minLength': 1,
|
|
348
|
+
'description': 'All valid special characters.',
|
|
349
|
+
},
|
|
350
|
+
'number:count': {
|
|
351
|
+
'type': ['number', 'null'],
|
|
352
|
+
'minimum': 0,
|
|
353
|
+
'description': 'The minimum number of digit characters required in password.',
|
|
354
|
+
},
|
|
355
|
+
'number:valid': {
|
|
356
|
+
'type': ['string', 'null'],
|
|
357
|
+
'minLength': 1,
|
|
358
|
+
'description': 'All valid digit characters.',
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
'additionalProperties': False,
|
|
362
|
+
},
|
|
363
|
+
'attempts': {
|
|
364
|
+
'type': ['number', 'null'],
|
|
365
|
+
'minimum': 1,
|
|
366
|
+
'description': 'Maximum number of incorrect attempts before locking user account.',
|
|
367
|
+
},
|
|
368
|
+
'previous': {
|
|
369
|
+
'type': ['number', 'null'],
|
|
370
|
+
'minimum': 1,
|
|
371
|
+
'description': 'Number of previous passwords to disallow.',
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
'additionalProperties': False,
|
|
375
|
+
}
|
|
376
|
+
reqValidPasswdPolicy = s_config.getJsValidator(_passwdPolicySchema)
|
|
377
|
+
|
|
291
378
|
# These types are order sensitive
|
|
292
379
|
_changelogTypes = {'migration': 'Automatic Migrations',
|
|
293
380
|
'model': 'Model Changes',
|
|
@@ -318,3 +405,52 @@ _changelogSchema = {
|
|
|
318
405
|
'required': ['type', 'desc']
|
|
319
406
|
}
|
|
320
407
|
_reqChanglogSchema = s_config.getJsValidator(_changelogSchema)
|
|
408
|
+
|
|
409
|
+
tabularConfSchema = {
|
|
410
|
+
'type': 'object',
|
|
411
|
+
'properties': {
|
|
412
|
+
'separators': {
|
|
413
|
+
'type': 'object',
|
|
414
|
+
'properties': {
|
|
415
|
+
'row:outline': {'type': 'boolean', 'default': False,
|
|
416
|
+
'description': 'Add the row separator before the header data and after each row.'},
|
|
417
|
+
'column:outline': {'type': 'boolean', 'default': False,
|
|
418
|
+
'description': 'Add the column separator to the beginning and end of each row.'},
|
|
419
|
+
'header:row': {'type': 'string', 'default': '=',
|
|
420
|
+
'description': 'The string to use to create a separator row when printing the header.'},
|
|
421
|
+
'data:row': {'type': 'string', 'default': '-',
|
|
422
|
+
'description': 'The string to use to create a separator row when printing data rows.'},
|
|
423
|
+
'column': {'type': 'string', 'default': '|',
|
|
424
|
+
'description': 'The string to use to separate columns.'},
|
|
425
|
+
},
|
|
426
|
+
'additionalProperties': False,
|
|
427
|
+
},
|
|
428
|
+
'columns': {
|
|
429
|
+
'type': 'array',
|
|
430
|
+
'items': {
|
|
431
|
+
'type': 'object',
|
|
432
|
+
'properties': {
|
|
433
|
+
'name': {'type': 'string',
|
|
434
|
+
'description': 'The column name which will be used in the header row.'},
|
|
435
|
+
'width': {'type': 'number', 'default': None, 'exclusiveMinimum': 0,
|
|
436
|
+
'description': 'If not provided each cell will expand to fit the data.'},
|
|
437
|
+
'justify': {'type': 'string', 'default': 'left', 'enum': ['left', 'center', 'right'],
|
|
438
|
+
'description': 'Justification for the header titles and data rows.'},
|
|
439
|
+
'overflow': {'type': 'string', 'default': 'trim', 'enum': ['wrap', 'trim'],
|
|
440
|
+
'description': 'For text exceeding the width, '
|
|
441
|
+
'either wrap text in multiple lines or trim and append "...".'},
|
|
442
|
+
'newlines': {'type': 'string', 'default': 'replace', 'enum': ['replace', 'split'],
|
|
443
|
+
'description': 'Replace newlines with a space or split into multiple lines.'
|
|
444
|
+
'Split is only applied if width is undefined.'},
|
|
445
|
+
},
|
|
446
|
+
'required': ['name'],
|
|
447
|
+
'minItems': 1,
|
|
448
|
+
'additionalProperties': False,
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
'required': ['columns'],
|
|
453
|
+
'additionalProperties': False,
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
reqValidTabularConf = s_config.getJsValidator(tabularConfSchema)
|
synapse/lib/storm.py
CHANGED
|
@@ -12,6 +12,7 @@ import synapse.telepath as s_telepath
|
|
|
12
12
|
import synapse.datamodel as s_datamodel
|
|
13
13
|
|
|
14
14
|
import synapse.lib.ast as s_ast
|
|
15
|
+
import synapse.lib.auth as s_auth
|
|
15
16
|
import synapse.lib.base as s_base
|
|
16
17
|
import synapse.lib.chop as s_chop
|
|
17
18
|
import synapse.lib.coro as s_coro
|
|
@@ -28,7 +29,6 @@ import synapse.lib.msgpack as s_msgpack
|
|
|
28
29
|
import synapse.lib.spooled as s_spooled
|
|
29
30
|
import synapse.lib.version as s_version
|
|
30
31
|
import synapse.lib.hashitem as s_hashitem
|
|
31
|
-
import synapse.lib.hiveauth as s_hiveauth
|
|
32
32
|
import synapse.lib.stormctrl as s_stormctrl
|
|
33
33
|
import synapse.lib.stormtypes as s_stormtypes
|
|
34
34
|
|
|
@@ -1066,7 +1066,7 @@ stormcmds = (
|
|
|
1066
1066
|
$lib.view.del($view.iden)
|
|
1067
1067
|
$lib.layer.del($layriden)
|
|
1068
1068
|
} else {
|
|
1069
|
-
$view.
|
|
1069
|
+
$view.swapLayer()
|
|
1070
1070
|
}
|
|
1071
1071
|
$lib.print("View merged: {iden}", iden=$cmdopts.iden)
|
|
1072
1072
|
''',
|
|
@@ -1831,7 +1831,7 @@ class Runtime(s_base.Base):
|
|
|
1831
1831
|
|
|
1832
1832
|
'''
|
|
1833
1833
|
|
|
1834
|
-
_admin_reason =
|
|
1834
|
+
_admin_reason = s_auth._allowedReason(True, isadmin=True)
|
|
1835
1835
|
async def __anit__(self, query, snap, opts=None, user=None, root=None):
|
|
1836
1836
|
|
|
1837
1837
|
await s_base.Base.__anit__(self)
|
|
@@ -3728,6 +3728,8 @@ class MergeCmd(Cmd):
|
|
|
3728
3728
|
pars = Cmd.getArgParser(self)
|
|
3729
3729
|
pars.add_argument('--apply', default=False, action='store_true',
|
|
3730
3730
|
help='Execute the merge changes.')
|
|
3731
|
+
pars.add_argument('--wipe', default=False, action='store_true',
|
|
3732
|
+
help='Replace the top layer in the view with a fresh layer.')
|
|
3731
3733
|
pars.add_argument('--no-tags', default=False, action='store_true',
|
|
3732
3734
|
help='Do not merge tags/tagprops or syn:tag nodes.')
|
|
3733
3735
|
pars.add_argument('--only-tags', default=False, action='store_true',
|
|
@@ -3801,13 +3803,15 @@ class MergeCmd(Cmd):
|
|
|
3801
3803
|
layr1 = runt.snap.view.layers[1].iden
|
|
3802
3804
|
|
|
3803
3805
|
if not allows['forms'] and sode.get('valu') is not None:
|
|
3804
|
-
|
|
3806
|
+
if not self.opts.wipe:
|
|
3807
|
+
runt.confirm(('node', 'del', node.form.name), gateiden=layr0)
|
|
3805
3808
|
runt.confirm(('node', 'add', node.form.name), gateiden=layr1)
|
|
3806
3809
|
|
|
3807
3810
|
if not allows['props']:
|
|
3808
3811
|
for name in sode.get('props', {}).keys():
|
|
3809
3812
|
prop = node.form.prop(name)
|
|
3810
|
-
|
|
3813
|
+
if not self.opts.wipe:
|
|
3814
|
+
runt.confirmPropDel(prop, layriden=layr0)
|
|
3811
3815
|
runt.confirmPropSet(prop, layriden=layr1)
|
|
3812
3816
|
|
|
3813
3817
|
if not allows['tags']:
|
|
@@ -3818,7 +3822,8 @@ class MergeCmd(Cmd):
|
|
|
3818
3822
|
if valu != (None, None):
|
|
3819
3823
|
tagadds.append(tag)
|
|
3820
3824
|
tagperm = tuple(tag.split('.'))
|
|
3821
|
-
|
|
3825
|
+
if not self.opts.wipe:
|
|
3826
|
+
runt.confirm(('node', 'tag', 'del') + tagperm, gateiden=layr0)
|
|
3822
3827
|
runt.confirm(('node', 'tag', 'add') + tagperm, gateiden=layr1)
|
|
3823
3828
|
else:
|
|
3824
3829
|
tags.append((len(tag), tag))
|
|
@@ -3830,22 +3835,26 @@ class MergeCmd(Cmd):
|
|
|
3830
3835
|
|
|
3831
3836
|
tagadds.append(tag)
|
|
3832
3837
|
tagperm = tuple(tag.split('.'))
|
|
3833
|
-
|
|
3838
|
+
if not self.opts.wipe:
|
|
3839
|
+
runt.confirm(('node', 'tag', 'del') + tagperm, gateiden=layr0)
|
|
3834
3840
|
runt.confirm(('node', 'tag', 'add') + tagperm, gateiden=layr1)
|
|
3835
3841
|
|
|
3836
3842
|
for tag in sode.get('tagprops', {}).keys():
|
|
3837
3843
|
tagperm = tuple(tag.split('.'))
|
|
3838
|
-
|
|
3844
|
+
if not self.opts.wipe:
|
|
3845
|
+
runt.confirm(('node', 'tag', 'del') + tagperm, gateiden=layr0)
|
|
3839
3846
|
runt.confirm(('node', 'tag', 'add') + tagperm, gateiden=layr1)
|
|
3840
3847
|
|
|
3841
3848
|
if not allows['ndata']:
|
|
3842
3849
|
async for name in runt.snap.view.layers[0].iterNodeDataKeys(node.buid):
|
|
3843
|
-
|
|
3850
|
+
if not self.opts.wipe:
|
|
3851
|
+
runt.confirm(('node', 'data', 'pop', name), gateiden=layr0)
|
|
3844
3852
|
runt.confirm(('node', 'data', 'set', name), gateiden=layr1)
|
|
3845
3853
|
|
|
3846
3854
|
if not allows['edges']:
|
|
3847
3855
|
async for verb in runt.snap.view.layers[0].iterNodeEdgeVerbsN1(node.buid):
|
|
3848
|
-
|
|
3856
|
+
if not self.opts.wipe:
|
|
3857
|
+
runt.confirm(('node', 'edge', 'del', verb), gateiden=layr0)
|
|
3849
3858
|
runt.confirm(('node', 'edge', 'add', verb), gateiden=layr1)
|
|
3850
3859
|
|
|
3851
3860
|
async def execStormCmd(self, runt, genr):
|
|
@@ -3854,6 +3863,11 @@ class MergeCmd(Cmd):
|
|
|
3854
3863
|
mesg = 'You may only merge nodes in forked views'
|
|
3855
3864
|
raise s_exc.CantMergeView(mesg=mesg)
|
|
3856
3865
|
|
|
3866
|
+
if self.opts.wipe:
|
|
3867
|
+
mesg = 'merge --wipe requires view admin'
|
|
3868
|
+
runt.reqAdmin(gateiden=runt.snap.view.iden, mesg=mesg)
|
|
3869
|
+
runt.confirm(('layer', 'del'), gateiden=runt.snap.view.layers[0].iden)
|
|
3870
|
+
|
|
3857
3871
|
notags = self.opts.no_tags
|
|
3858
3872
|
onlytags = self.opts.only_tags
|
|
3859
3873
|
doapply = self.opts.apply
|
|
@@ -3867,18 +3881,27 @@ class MergeCmd(Cmd):
|
|
|
3867
3881
|
doperms = doapply and not (runt.isAdmin(gateiden=layr0.iden) and runt.isAdmin(gateiden=layr1.iden))
|
|
3868
3882
|
|
|
3869
3883
|
if doperms:
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3884
|
+
if not self.opts.wipe:
|
|
3885
|
+
allows = {
|
|
3886
|
+
'forms': runt.user.allowed(('node', 'del'), gateiden=layr0.iden, deepdeny=True) and
|
|
3887
|
+
runt.user.allowed(('node', 'add'), gateiden=layr1.iden, deepdeny=True),
|
|
3888
|
+
'props': runt.user.allowed(('node', 'prop', 'del'), gateiden=layr0.iden, deepdeny=True) and
|
|
3889
|
+
runt.user.allowed(('node', 'prop', 'set'), gateiden=layr1.iden, deepdeny=True),
|
|
3890
|
+
'tags': runt.user.allowed(('node', 'tag', 'del'), gateiden=layr0.iden, deepdeny=True) and
|
|
3891
|
+
runt.user.allowed(('node', 'tag', 'add'), gateiden=layr1.iden, deepdeny=True),
|
|
3892
|
+
'ndata': runt.user.allowed(('node', 'data', 'pop'), gateiden=layr0.iden, deepdeny=True) and
|
|
3893
|
+
runt.user.allowed(('node', 'data', 'set'), gateiden=layr1.iden, deepdeny=True),
|
|
3894
|
+
'edges': runt.user.allowed(('node', 'edge', 'del'), gateiden=layr0.iden, deepdeny=True) and
|
|
3895
|
+
runt.user.allowed(('node', 'edge', 'add'), gateiden=layr1.iden, deepdeny=True),
|
|
3896
|
+
}
|
|
3897
|
+
else:
|
|
3898
|
+
allows = {
|
|
3899
|
+
'forms': runt.user.allowed(('node', 'add'), gateiden=layr1.iden, deepdeny=True),
|
|
3900
|
+
'props': runt.user.allowed(('node', 'prop', 'set'), gateiden=layr1.iden, deepdeny=True),
|
|
3901
|
+
'tags': runt.user.allowed(('node', 'tag', 'add'), gateiden=layr1.iden, deepdeny=True),
|
|
3902
|
+
'ndata': runt.user.allowed(('node', 'data', 'set'), gateiden=layr1.iden, deepdeny=True),
|
|
3903
|
+
'edges': runt.user.allowed(('node', 'edge', 'add'), gateiden=layr1.iden, deepdeny=True),
|
|
3904
|
+
}
|
|
3882
3905
|
|
|
3883
3906
|
doperms = not all(allows.values())
|
|
3884
3907
|
|
|
@@ -3966,7 +3989,8 @@ class MergeCmd(Cmd):
|
|
|
3966
3989
|
if name == '.created':
|
|
3967
3990
|
if doapply:
|
|
3968
3991
|
protonode.props['.created'] = valu
|
|
3969
|
-
|
|
3992
|
+
if not self.opts.wipe:
|
|
3993
|
+
subs.append((s_layer.EDIT_PROP_DEL, (name, valu, stortype), ()))
|
|
3970
3994
|
continue
|
|
3971
3995
|
|
|
3972
3996
|
isset = False
|
|
@@ -3990,7 +4014,8 @@ class MergeCmd(Cmd):
|
|
|
3990
4014
|
await runt.printf(f'{nodeiden} {form}:{name} = {valurepr}')
|
|
3991
4015
|
else:
|
|
3992
4016
|
await protonode.set(name, valu)
|
|
3993
|
-
|
|
4017
|
+
if not self.opts.wipe:
|
|
4018
|
+
subs.append((s_layer.EDIT_PROP_DEL, (name, valu, stortype), ()))
|
|
3994
4019
|
|
|
3995
4020
|
if doapply and protonode is None:
|
|
3996
4021
|
protonode = await editor.addNode(form, node.ndef[1], norminfo={})
|
|
@@ -4009,7 +4034,8 @@ class MergeCmd(Cmd):
|
|
|
4009
4034
|
await runt.printf(f'{nodeiden} {form}#{tag}{valurepr}')
|
|
4010
4035
|
else:
|
|
4011
4036
|
await protonode.addTag(tag, valu)
|
|
4012
|
-
|
|
4037
|
+
if not self.opts.wipe:
|
|
4038
|
+
subs.append((s_layer.EDIT_TAG_DEL, (tag, valu), ()))
|
|
4013
4039
|
|
|
4014
4040
|
for tag, tagdict in sode.get('tagprops', {}).items():
|
|
4015
4041
|
|
|
@@ -4022,7 +4048,8 @@ class MergeCmd(Cmd):
|
|
|
4022
4048
|
await runt.printf(f'{nodeiden} {form}#{tag}:{prop} = {valurepr}')
|
|
4023
4049
|
else:
|
|
4024
4050
|
await protonode.setTagProp(tag, prop, valu)
|
|
4025
|
-
|
|
4051
|
+
if not self.opts.wipe:
|
|
4052
|
+
subs.append((s_layer.EDIT_TAGPROP_DEL, (tag, prop, valu, stortype), ()))
|
|
4026
4053
|
|
|
4027
4054
|
if not onlytags or form == 'syn:tag':
|
|
4028
4055
|
|
|
@@ -4032,7 +4059,8 @@ class MergeCmd(Cmd):
|
|
|
4032
4059
|
await runt.printf(f'{nodeiden} {form} DATA {name} = {valurepr}')
|
|
4033
4060
|
else:
|
|
4034
4061
|
await protonode.setData(name, valu)
|
|
4035
|
-
|
|
4062
|
+
if not self.opts.wipe:
|
|
4063
|
+
subs.append((s_layer.EDIT_NODEDATA_DEL, (name, valu), ()))
|
|
4036
4064
|
|
|
4037
4065
|
async for edge in s_coro.pause(layr0.iterNodeEdgesN1(node.buid)):
|
|
4038
4066
|
name, dest = edge
|
|
@@ -4040,9 +4068,10 @@ class MergeCmd(Cmd):
|
|
|
4040
4068
|
await runt.printf(f'{nodeiden} {form} +({name})> {dest}')
|
|
4041
4069
|
else:
|
|
4042
4070
|
await protonode.addEdge(name, dest)
|
|
4043
|
-
|
|
4071
|
+
if not self.opts.wipe:
|
|
4072
|
+
subs.append((s_layer.EDIT_EDGE_DEL, edge, ()))
|
|
4044
4073
|
|
|
4045
|
-
if delnode:
|
|
4074
|
+
if delnode and not self.opts.wipe:
|
|
4046
4075
|
subs.append((s_layer.EDIT_NODE_DEL, valu, ()))
|
|
4047
4076
|
|
|
4048
4077
|
if doapply:
|
|
@@ -4057,6 +4086,9 @@ class MergeCmd(Cmd):
|
|
|
4057
4086
|
runt.snap.clearCachedNode(node.buid)
|
|
4058
4087
|
yield await runt.snap.getNodeByBuid(node.buid), path
|
|
4059
4088
|
|
|
4089
|
+
if doapply and self.opts.wipe:
|
|
4090
|
+
await runt.snap.view.swapLayer()
|
|
4091
|
+
|
|
4060
4092
|
class MoveNodesCmd(Cmd):
|
|
4061
4093
|
'''
|
|
4062
4094
|
Move storage nodes between layers.
|
synapse/lib/stormlib/aha.py
CHANGED
|
@@ -486,7 +486,7 @@ The ready column indicates that a service has entered into the realtime change w
|
|
|
486
486
|
if $svcinfo.online {
|
|
487
487
|
$nexusOffset = $_getNexus($name)
|
|
488
488
|
} else {
|
|
489
|
-
$nexusOffset = '
|
|
489
|
+
$nexusOffset = '<offline>'
|
|
490
490
|
}
|
|
491
491
|
}
|
|
492
492
|
$name=$name.ljust(45)
|