synapse 2.224.0__py311-none-any.whl → 2.225.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 +10 -5
- synapse/lib/cell.py +1 -1
- synapse/lib/const.py +4 -0
- synapse/lib/multislabseqn.py +36 -1
- synapse/lib/nexus.py +67 -8
- synapse/lib/queue.py +4 -1
- synapse/lib/rstorm.py +2 -2
- synapse/lib/schemas.py +11 -1
- synapse/lib/slabseqn.py +28 -0
- synapse/lib/storm.py +5 -1
- synapse/lib/stormhttp.py +7 -1
- synapse/lib/version.py +2 -2
- synapse/models/inet.py +4 -0
- synapse/models/media.py +4 -0
- synapse/models/risk.py +3 -0
- synapse/tests/test_cortex.py +2 -2
- synapse/tests/test_lib_agenda.py +1 -1
- synapse/tests/test_lib_cell.py +1 -1
- synapse/tests/test_lib_certdir.py +1 -1
- synapse/tests/test_lib_httpapi.py +1 -1
- synapse/tests/test_lib_layer.py +1 -1
- synapse/tests/test_lib_multislabseqn.py +22 -0
- synapse/tests/test_lib_nexus.py +42 -1
- synapse/tests/test_lib_slabseqn.py +30 -1
- synapse/tests/test_lib_storm.py +59 -1
- synapse/tests/test_lib_stormhttp.py +16 -0
- synapse/tests/test_lib_stormlib_oauth.py +1 -1
- synapse/tests/test_lib_stormsvc.py +1 -1
- synapse/tests/test_lib_trigger.py +1 -1
- synapse/tests/test_model_inet.py +6 -0
- synapse/tests/test_model_media.py +4 -1
- synapse/tests/test_model_risk.py +2 -0
- synapse/tests/{test_tools_axon2axon.py → test_tools_axon_copy.py} +4 -4
- synapse/tests/{test_tools_pullfile.py → test_tools_axon_get.py} +4 -4
- synapse/tests/{test_tools_pushfile.py → test_tools_axon_put.py} +7 -7
- synapse/tests/{test_tools_csvtool.py → test_tools_cortex_csv.py} +12 -3
- synapse/tests/{test_tools_feed.py → test_tools_cortex_feed.py} +2 -2
- synapse/tests/{test_tools_apikey.py → test_tools_service_apikey.py} +1 -4
- synapse/tests/{test_tools_backup.py → test_tools_service_backup.py} +5 -5
- synapse/tests/{test_tools_demote.py → test_tools_service_demote.py} +1 -1
- synapse/tests/{test_tools_healthcheck.py → test_tools_service_healthcheck.py} +1 -1
- synapse/tests/{test_tools_livebackup.py → test_tools_service_livebackup.py} +1 -1
- synapse/tests/{test_tools_modrole.py → test_tools_service_modrole.py} +1 -1
- synapse/tests/{test_tools_moduser.py → test_tools_service_moduser.py} +1 -1
- synapse/tests/{test_tools_promote.py → test_tools_service_promote.py} +1 -1
- synapse/tests/{test_tools_reload.py → test_tools_service_reload.py} +1 -1
- synapse/tests/{test_tools_shutdown.py → test_tools_service_shutdown.py} +1 -1
- synapse/tests/{test_tools_snapshot.py → test_tools_service_snapshot.py} +1 -1
- synapse/tests/{test_tools_storm.py → test_tools_storm_cli.py} +1 -1
- synapse/tests/{test_tools_pkgs_gendocs.py → test_tools_storm_pkg_doc.py} +12 -3
- synapse/tests/{test_tools_genpkg.py → test_tools_storm_pkg_gen.py} +1 -1
- synapse/tests/{test_tools_autodoc.py → test_tools_utils_autodoc.py} +1 -1
- synapse/tests/test_tools_utils_changelog.py +454 -0
- synapse/tests/{test_tools_easycert.py → test_tools_utils_easycert.py} +48 -46
- synapse/tests/{test_tools_guid.py → test_tools_utils_guid.py} +3 -3
- synapse/tests/{test_tools_json2mpk.py → test_tools_utils_json2mpk.py} +3 -3
- synapse/tests/{test_tools_rstorm.py → test_tools_utils_rstorm.py} +6 -1
- synapse/tests/utils.py +3 -1
- synapse/tools/apikey.py +4 -83
- synapse/tools/autodoc.py +3 -1031
- synapse/tools/axon/copy.py +44 -0
- synapse/tools/axon/get.py +64 -0
- synapse/tools/axon/put.py +122 -0
- synapse/tools/axon2axon.py +3 -36
- synapse/tools/backup.py +6 -176
- synapse/tools/changelog.py +3 -1098
- synapse/tools/cortex/csv.py +236 -0
- synapse/tools/cortex/feed.py +151 -0
- synapse/tools/csvtool.py +3 -227
- synapse/tools/demote.py +4 -40
- synapse/tools/docker/validate.py +3 -3
- synapse/tools/easycert.py +4 -129
- synapse/tools/feed.py +3 -140
- synapse/tools/genpkg.py +3 -307
- synapse/tools/guid.py +7 -6
- synapse/tools/healthcheck.py +3 -101
- synapse/tools/json2mpk.py +6 -38
- synapse/tools/livebackup.py +4 -27
- synapse/tools/modrole.py +3 -108
- synapse/tools/moduser.py +3 -179
- synapse/tools/pkgs/gendocs.py +3 -164
- synapse/tools/promote.py +4 -41
- synapse/tools/pullfile.py +3 -56
- synapse/tools/pushfile.py +3 -114
- synapse/tools/reload.py +4 -61
- synapse/tools/rstorm.py +3 -26
- synapse/tools/service/__init__.py +0 -0
- synapse/tools/service/apikey.py +90 -0
- synapse/tools/service/backup.py +181 -0
- synapse/tools/service/demote.py +47 -0
- synapse/tools/service/healthcheck.py +109 -0
- synapse/tools/service/livebackup.py +34 -0
- synapse/tools/service/modrole.py +116 -0
- synapse/tools/service/moduser.py +184 -0
- synapse/tools/service/promote.py +48 -0
- synapse/tools/service/reload.py +68 -0
- synapse/tools/service/shutdown.py +51 -0
- synapse/tools/service/snapshot.py +64 -0
- synapse/tools/shutdown.py +5 -45
- synapse/tools/snapshot.py +4 -57
- synapse/tools/storm/__init__.py +0 -0
- synapse/tools/storm/__main__.py +5 -0
- synapse/tools/{storm.py → storm/_cli.py} +0 -3
- synapse/tools/storm/pkg/__init__.py +0 -0
- synapse/tools/{pkgs/pandoc_filter.py → storm/pkg/_pandoc_filter.py} +1 -1
- synapse/tools/storm/pkg/doc.py +176 -0
- synapse/tools/storm/pkg/gen.py +315 -0
- synapse/tools/utils/__init__.py +0 -0
- synapse/tools/utils/autodoc.py +1040 -0
- synapse/tools/utils/changelog.py +1124 -0
- synapse/tools/utils/easycert.py +136 -0
- synapse/tools/utils/guid.py +11 -0
- synapse/tools/utils/json2mpk.py +46 -0
- synapse/tools/utils/rstorm.py +35 -0
- {synapse-2.224.0.dist-info → synapse-2.225.0.dist-info}/METADATA +1 -1
- {synapse-2.224.0.dist-info → synapse-2.225.0.dist-info}/RECORD +120 -91
- synapse/tests/test_tools_changelog.py +0 -196
- /synapse/tests/{test_tools_axon.py → test_tools_axon_dump_load.py} +0 -0
- {synapse-2.224.0.dist-info → synapse-2.225.0.dist-info}/WHEEL +0 -0
- {synapse-2.224.0.dist-info → synapse-2.225.0.dist-info}/licenses/LICENSE +0 -0
- {synapse-2.224.0.dist-info → synapse-2.225.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import asyncio
|
|
3
|
+
|
|
4
|
+
import synapse.exc as s_exc
|
|
5
|
+
import synapse.common as s_common
|
|
6
|
+
import synapse.telepath as s_telepath
|
|
7
|
+
|
|
8
|
+
import synapse.lib.cmd as s_cmd
|
|
9
|
+
import synapse.lib.json as s_json
|
|
10
|
+
import synapse.lib.output as s_output
|
|
11
|
+
import synapse.lib.health as s_health
|
|
12
|
+
import synapse.lib.urlhelp as s_urlhelp
|
|
13
|
+
|
|
14
|
+
def serialize(ret):
|
|
15
|
+
return s_json.dumps(ret).decode()
|
|
16
|
+
|
|
17
|
+
def format_component(e, mesg: str) -> dict:
|
|
18
|
+
d = {
|
|
19
|
+
'name': 'error',
|
|
20
|
+
'status': s_health.FAILED,
|
|
21
|
+
'mesg': mesg,
|
|
22
|
+
'data': {
|
|
23
|
+
'errname': e.__class__.__name__,
|
|
24
|
+
'errmesg': str(e),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return d
|
|
29
|
+
|
|
30
|
+
async def main(argv, outp=s_output.stdout):
|
|
31
|
+
pars = getArgParser(outp)
|
|
32
|
+
try:
|
|
33
|
+
opts = pars.parse_args(argv)
|
|
34
|
+
except s_exc.ParserExit as e: # pragma: no cover
|
|
35
|
+
return e.get('status')
|
|
36
|
+
|
|
37
|
+
url = opts.cell
|
|
38
|
+
sanitized_url = s_urlhelp.sanitizeUrl(url)
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
async with s_telepath.withTeleEnv():
|
|
42
|
+
|
|
43
|
+
prox = await s_common.wait_for(s_telepath.openurl(url),
|
|
44
|
+
timeout=opts.timeout)
|
|
45
|
+
except (s_exc.LinkErr, s_exc.NoSuchPath, socket.gaierror) as e:
|
|
46
|
+
mesg = f'Unable to connect to cell @ {sanitized_url}.'
|
|
47
|
+
ret = {'status': 'failed',
|
|
48
|
+
'iden': opts.cell,
|
|
49
|
+
'components': [format_component(e, mesg)],
|
|
50
|
+
}
|
|
51
|
+
outp.printf(serialize(ret))
|
|
52
|
+
return 1
|
|
53
|
+
except s_exc.SynErr as e:
|
|
54
|
+
mesg = 'Synapse error encountered.'
|
|
55
|
+
ret = {'status': s_health.FAILED,
|
|
56
|
+
'iden': opts.cell,
|
|
57
|
+
'components': [format_component(e, mesg)],
|
|
58
|
+
}
|
|
59
|
+
outp.printf(serialize(ret))
|
|
60
|
+
return 1
|
|
61
|
+
except asyncio.TimeoutError as e: # pragma: no cover
|
|
62
|
+
mesg = 'Timeout connecting to cell'
|
|
63
|
+
ret = {'status': s_health.FAILED,
|
|
64
|
+
'iden': opts.cell,
|
|
65
|
+
'components': [format_component(e, mesg)],
|
|
66
|
+
}
|
|
67
|
+
outp.printf(serialize(ret))
|
|
68
|
+
return 1
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
ret = await s_common.wait_for(prox.getHealthCheck(),
|
|
72
|
+
timeout=opts.timeout)
|
|
73
|
+
except s_exc.SynErr as e:
|
|
74
|
+
mesg = 'Synapse error encountered.'
|
|
75
|
+
ret = {'status': s_health.FAILED,
|
|
76
|
+
'iden': opts.cell,
|
|
77
|
+
'components': [format_component(e, mesg)],
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
except asyncio.TimeoutError as e:
|
|
81
|
+
mesg = 'Timeout getting health information from cell.'
|
|
82
|
+
ret = {'status': s_health.FAILED,
|
|
83
|
+
'iden': opts.cell,
|
|
84
|
+
'components': [format_component(e, mesg)],
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
finally:
|
|
88
|
+
await prox.fini()
|
|
89
|
+
|
|
90
|
+
retval = 1
|
|
91
|
+
if ret.get('status') in (s_health.NOMINAL, s_health.DEGRADED):
|
|
92
|
+
retval = 0
|
|
93
|
+
|
|
94
|
+
outp.printf(serialize(ret))
|
|
95
|
+
return retval
|
|
96
|
+
|
|
97
|
+
def getArgParser(outp):
|
|
98
|
+
desc = '''
|
|
99
|
+
synapse healthcheck tool
|
|
100
|
+
'''
|
|
101
|
+
pars = s_cmd.Parser(prog='synapse.tools.service.healthcheck', outp=outp, description=desc)
|
|
102
|
+
pars.add_argument('--cell', '-c', required=True, type=str,
|
|
103
|
+
help='Telepath path to the cell to check.')
|
|
104
|
+
pars.add_argument('--timeout', '-t', default=10, type=float,
|
|
105
|
+
help='Connection and call timeout')
|
|
106
|
+
return pars
|
|
107
|
+
|
|
108
|
+
if __name__ == '__main__': # pragma: no cover
|
|
109
|
+
s_cmd.exitmain(main)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import synapse.telepath as s_telepath
|
|
2
|
+
|
|
3
|
+
import synapse.lib.cmd as s_cmd
|
|
4
|
+
import synapse.lib.output as s_output
|
|
5
|
+
|
|
6
|
+
descr = '''
|
|
7
|
+
Generate a new backup of a running Synapse service.
|
|
8
|
+
|
|
9
|
+
Examples:
|
|
10
|
+
|
|
11
|
+
# Generate a backup from inside a Synapse service container
|
|
12
|
+
python -m synapse.tools.service.livebackup
|
|
13
|
+
|
|
14
|
+
'''
|
|
15
|
+
|
|
16
|
+
async def main(argv, outp=s_output.stdout):
|
|
17
|
+
|
|
18
|
+
pars = s_cmd.Parser(prog='synapse.tools.service.livebackup', outp=outp, description=descr)
|
|
19
|
+
|
|
20
|
+
pars.add_argument('--url', default='cell:///vertex/storage', help='The telepath URL of the Synapse service.')
|
|
21
|
+
pars.add_argument('--name', default=None, help='Specify a name for the backup. Defaults to an automatically generated timestamp.')
|
|
22
|
+
|
|
23
|
+
opts = pars.parse_args(argv)
|
|
24
|
+
|
|
25
|
+
async with s_telepath.withTeleEnv():
|
|
26
|
+
|
|
27
|
+
async with await s_telepath.openurl(opts.url) as cell:
|
|
28
|
+
outp.printf(f'Running backup of: {opts.url}')
|
|
29
|
+
name = await cell.runBackup(name=opts.name)
|
|
30
|
+
outp.printf(f'...backup created: {name}')
|
|
31
|
+
return 0
|
|
32
|
+
|
|
33
|
+
if __name__ == '__main__': # pragma: no cover
|
|
34
|
+
s_cmd.exitmain(main)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import synapse.common as s_common
|
|
2
|
+
import synapse.telepath as s_telepath
|
|
3
|
+
|
|
4
|
+
import synapse.lib.cmd as s_cmd
|
|
5
|
+
import synapse.lib.output as s_output
|
|
6
|
+
|
|
7
|
+
descr = '''
|
|
8
|
+
Add or modify a role in a Synapse service.
|
|
9
|
+
'''
|
|
10
|
+
|
|
11
|
+
def printrole(role, outp):
|
|
12
|
+
|
|
13
|
+
outp.printf(f'Role: {role.get("name")} ({role.get("iden")})')
|
|
14
|
+
outp.printf('')
|
|
15
|
+
outp.printf(' Rules:')
|
|
16
|
+
for indx, rule in enumerate(role.get('rules')):
|
|
17
|
+
outp.printf(f' [{str(indx).ljust(3)}] - {s_common.reprauthrule(rule)}')
|
|
18
|
+
|
|
19
|
+
outp.printf('')
|
|
20
|
+
outp.printf(' Gates:')
|
|
21
|
+
for gateiden, gateinfo in role.get('authgates', {}).items():
|
|
22
|
+
outp.printf(f' {gateiden}')
|
|
23
|
+
outp.printf(f' Admin: {gateinfo.get("admin") == True}')
|
|
24
|
+
for indx, rule in enumerate(gateinfo.get('rules', ())):
|
|
25
|
+
outp.printf(f' [{str(indx).ljust(3)}] - {s_common.reprauthrule(rule)}')
|
|
26
|
+
|
|
27
|
+
async def main(argv, outp=s_output.stdout):
|
|
28
|
+
|
|
29
|
+
pars = s_cmd.Parser(prog='synapse.tools.service.modrole', outp=outp, description=descr)
|
|
30
|
+
pars.add_argument('--svcurl', default='cell:///vertex/storage', help='The telepath URL of the Synapse service.')
|
|
31
|
+
pars.add_argument('--add', default=False, action='store_true', help='Add the role if they do not already exist.')
|
|
32
|
+
pars.add_argument('--del', dest='delete', default=False, action='store_true', help='Delete the role if it exists.')
|
|
33
|
+
pars.add_argument('--list', default=False, action='store_true',
|
|
34
|
+
help='List existing roles, or rules of a specific role.')
|
|
35
|
+
pars.add_argument('--allow', default=[], action='append', help='A permission string to allow for the role.')
|
|
36
|
+
pars.add_argument('--deny', default=[], action='append', help='A permission string to deny for the role.')
|
|
37
|
+
pars.add_argument('--gate', default=None, help='The iden of an auth gate to add/del rules on.')
|
|
38
|
+
pars.add_argument('rolename', nargs='?', help='The rolename to add/edit.')
|
|
39
|
+
|
|
40
|
+
opts = pars.parse_args(argv)
|
|
41
|
+
|
|
42
|
+
if opts.add and opts.delete:
|
|
43
|
+
outp.printf('ERROR: Cannot specify --add and --del together.')
|
|
44
|
+
return 1
|
|
45
|
+
|
|
46
|
+
async with s_telepath.withTeleEnv():
|
|
47
|
+
|
|
48
|
+
async with await s_telepath.openurl(opts.svcurl) as cell:
|
|
49
|
+
|
|
50
|
+
if opts.list:
|
|
51
|
+
if opts.rolename:
|
|
52
|
+
role = await cell.getRoleDefByName(opts.rolename)
|
|
53
|
+
if role is None:
|
|
54
|
+
outp.printf(f'ERROR: Role not found: {opts.rolename}')
|
|
55
|
+
return 1
|
|
56
|
+
|
|
57
|
+
printrole(role, outp)
|
|
58
|
+
|
|
59
|
+
else:
|
|
60
|
+
outp.printf('Roles:')
|
|
61
|
+
for role in await cell.getRoleDefs():
|
|
62
|
+
outp.printf(f' {role.get("iden")} - {role.get("name")}')
|
|
63
|
+
|
|
64
|
+
return 0
|
|
65
|
+
elif opts.rolename is None:
|
|
66
|
+
outp.printf(f'ERROR: A rolename argument is required when --list is not specified.')
|
|
67
|
+
return 1
|
|
68
|
+
|
|
69
|
+
if opts.gate:
|
|
70
|
+
gate = await cell.getAuthGate(opts.gate)
|
|
71
|
+
if gate is None:
|
|
72
|
+
outp.printf(f'ERROR: No auth gate found with iden: {opts.gate}')
|
|
73
|
+
return 1
|
|
74
|
+
|
|
75
|
+
role = await cell.getRoleDefByName(opts.rolename)
|
|
76
|
+
if role is not None:
|
|
77
|
+
outp.printf(f'Modifying role: {opts.rolename}')
|
|
78
|
+
|
|
79
|
+
if role is None:
|
|
80
|
+
if not opts.add:
|
|
81
|
+
outp.printf(f'ERROR: Role not found (need --add?): {opts.rolename}')
|
|
82
|
+
return 1
|
|
83
|
+
|
|
84
|
+
outp.printf(f'Adding role: {opts.rolename}')
|
|
85
|
+
role = await cell.addRole(opts.rolename)
|
|
86
|
+
|
|
87
|
+
roleiden = role.get('iden')
|
|
88
|
+
|
|
89
|
+
if opts.delete:
|
|
90
|
+
outp.printf(f'...deleting role: {opts.rolename}')
|
|
91
|
+
await cell.delRole(roleiden)
|
|
92
|
+
return 0
|
|
93
|
+
|
|
94
|
+
for allow in opts.allow:
|
|
95
|
+
perm = allow.lower().split('.')
|
|
96
|
+
mesg = f'...adding allow rule: {allow}'
|
|
97
|
+
if opts.gate:
|
|
98
|
+
mesg += f' on gate {opts.gate}'
|
|
99
|
+
|
|
100
|
+
outp.printf(mesg)
|
|
101
|
+
if not await cell.isRoleAllowed(roleiden, perm, gateiden=opts.gate):
|
|
102
|
+
await cell.addRoleRule(roleiden, (True, perm), indx=0, gateiden=opts.gate)
|
|
103
|
+
|
|
104
|
+
for deny in opts.deny:
|
|
105
|
+
perm = deny.lower().split('.')
|
|
106
|
+
mesg = f'...adding deny rule: {deny}'
|
|
107
|
+
if opts.gate:
|
|
108
|
+
mesg += f' on gate {opts.gate}'
|
|
109
|
+
|
|
110
|
+
outp.printf(mesg)
|
|
111
|
+
if await cell.isRoleAllowed(roleiden, perm, gateiden=opts.gate):
|
|
112
|
+
await cell.addRoleRule(roleiden, (False, perm), indx=0, gateiden=opts.gate)
|
|
113
|
+
return 0
|
|
114
|
+
|
|
115
|
+
if __name__ == '__main__': # pragma: no cover
|
|
116
|
+
s_cmd.exitmain(main)
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import synapse.common as s_common
|
|
2
|
+
import synapse.telepath as s_telepath
|
|
3
|
+
|
|
4
|
+
import synapse.lib.cmd as s_cmd
|
|
5
|
+
import synapse.lib.output as s_output
|
|
6
|
+
|
|
7
|
+
descr = '''
|
|
8
|
+
Add, modify, or list users of a Synapse service.
|
|
9
|
+
'''
|
|
10
|
+
|
|
11
|
+
def printuser(user, outp):
|
|
12
|
+
|
|
13
|
+
outp.printf(f'User: {user.get("name")} ({user.get("iden")})')
|
|
14
|
+
outp.printf('')
|
|
15
|
+
outp.printf(f' Locked: {user.get("locked")}')
|
|
16
|
+
outp.printf(f' Admin: {user.get("admin")}')
|
|
17
|
+
outp.printf(f' Email: {user.get("email")}')
|
|
18
|
+
outp.printf(' Rules:')
|
|
19
|
+
for indx, rule in enumerate(user.get('rules')):
|
|
20
|
+
outp.printf(f' [{str(indx).ljust(3)}] - {s_common.reprauthrule(rule)}')
|
|
21
|
+
|
|
22
|
+
outp.printf('')
|
|
23
|
+
outp.printf(' Roles:')
|
|
24
|
+
for role in user.get('roles'):
|
|
25
|
+
outp.printf(f' {role.get("iden")} - {role.get("name")}')
|
|
26
|
+
|
|
27
|
+
outp.printf('')
|
|
28
|
+
outp.printf(' Gates:')
|
|
29
|
+
for gateiden, gateinfo in user.get('authgates', {}).items():
|
|
30
|
+
outp.printf(f' {gateiden}')
|
|
31
|
+
outp.printf(f' Admin: {gateinfo.get("admin") == True}')
|
|
32
|
+
for indx, rule in enumerate(gateinfo.get('rules', ())):
|
|
33
|
+
outp.printf(f' [{str(indx).ljust(3)}] - {s_common.reprauthrule(rule)}')
|
|
34
|
+
|
|
35
|
+
async def main(argv, outp=s_output.stdout):
|
|
36
|
+
|
|
37
|
+
pars = s_cmd.Parser(prog='synapse.tools.service.moduser', outp=outp, description=descr)
|
|
38
|
+
pars.add_argument('--svcurl', default='cell:///vertex/storage', help='The telepath URL of the Synapse service.')
|
|
39
|
+
pars.add_argument('--add', default=False, action='store_true', help='Add the user if they do not already exist.')
|
|
40
|
+
pars.add_argument('--del', dest='delete', default=False, action='store_true', help='Delete the user if they exist.')
|
|
41
|
+
pars.add_argument('--list', default=False, action='store_true',
|
|
42
|
+
help='List existing users of the service, or details of a specific user.')
|
|
43
|
+
pars.add_argument('--admin', choices=('true', 'false'), default=None, help='Set the user admin status.')
|
|
44
|
+
pars.add_argument('--passwd', action='store', type=str, help='A password to set for the user.')
|
|
45
|
+
pars.add_argument('--email', action='store', type=str, help='An email to set for the user.')
|
|
46
|
+
pars.add_argument('--locked', choices=('true', 'false'), default=None, help='Set the user locked status.')
|
|
47
|
+
pars.add_argument('--grant', default=[], action='append', help='A role to grant to the user.')
|
|
48
|
+
pars.add_argument('--revoke', default=[], action='append', help='A role to revoke from the user.')
|
|
49
|
+
pars.add_argument('--allow', default=[], action='append', help='A permission string to allow for the user.')
|
|
50
|
+
pars.add_argument('--deny', default=[], action='append', help='A permission string to deny for the user.')
|
|
51
|
+
pars.add_argument('--gate', default=None, help='The iden of an auth gate to add/del rules or set admin status on.')
|
|
52
|
+
pars.add_argument('username', nargs='?', help='The username to add/edit or show details.')
|
|
53
|
+
|
|
54
|
+
opts = pars.parse_args(argv)
|
|
55
|
+
|
|
56
|
+
if opts.add and opts.delete:
|
|
57
|
+
outp.printf('ERROR: Cannot specify --add and --del together.')
|
|
58
|
+
return 1
|
|
59
|
+
|
|
60
|
+
async with s_telepath.withTeleEnv():
|
|
61
|
+
|
|
62
|
+
async with await s_telepath.openurl(opts.svcurl) as cell:
|
|
63
|
+
|
|
64
|
+
if opts.list:
|
|
65
|
+
if opts.username:
|
|
66
|
+
user = await cell.getUserDefByName(opts.username)
|
|
67
|
+
if user is None:
|
|
68
|
+
outp.printf(f'ERROR: User not found: {opts.username}')
|
|
69
|
+
return 1
|
|
70
|
+
|
|
71
|
+
printuser(user, outp)
|
|
72
|
+
|
|
73
|
+
else:
|
|
74
|
+
outp.printf('Users:')
|
|
75
|
+
for user in await cell.getUserDefs():
|
|
76
|
+
outp.printf(f' {user.get("name")}')
|
|
77
|
+
|
|
78
|
+
return 0
|
|
79
|
+
|
|
80
|
+
elif opts.username is None:
|
|
81
|
+
outp.printf(f'ERROR: A username argument is required when --list is not specified.')
|
|
82
|
+
return 1
|
|
83
|
+
|
|
84
|
+
if opts.gate:
|
|
85
|
+
gate = await cell.getAuthGate(opts.gate)
|
|
86
|
+
if gate is None:
|
|
87
|
+
outp.printf(f'ERROR: No auth gate found with iden: {opts.gate}')
|
|
88
|
+
return 1
|
|
89
|
+
|
|
90
|
+
grants = []
|
|
91
|
+
revokes = []
|
|
92
|
+
|
|
93
|
+
for rolename in opts.grant:
|
|
94
|
+
role = await cell.getRoleDefByName(rolename)
|
|
95
|
+
if role is None:
|
|
96
|
+
outp.printf(f'ERROR: Role not found: {rolename}')
|
|
97
|
+
return 1
|
|
98
|
+
grants.append(role)
|
|
99
|
+
|
|
100
|
+
for rolename in opts.revoke:
|
|
101
|
+
role = await cell.getRoleDefByName(rolename)
|
|
102
|
+
if role is None:
|
|
103
|
+
outp.printf(f'ERROR: Role not found: {rolename}')
|
|
104
|
+
return 1
|
|
105
|
+
revokes.append(role)
|
|
106
|
+
|
|
107
|
+
user = await cell.getUserDefByName(opts.username)
|
|
108
|
+
|
|
109
|
+
if user is None:
|
|
110
|
+
if not opts.add:
|
|
111
|
+
outp.printf(f'ERROR: User not found (need --add?): {opts.username}')
|
|
112
|
+
return 1
|
|
113
|
+
|
|
114
|
+
outp.printf(f'Adding user: {opts.username}')
|
|
115
|
+
user = await cell.addUser(opts.username)
|
|
116
|
+
|
|
117
|
+
else:
|
|
118
|
+
outp.printf(f'Modifying user: {opts.username}')
|
|
119
|
+
|
|
120
|
+
useriden = user.get('iden')
|
|
121
|
+
if not s_common.isguid(useriden): # pragma: no cover
|
|
122
|
+
outp.printf(f'ERROR: Invalid useriden: {useriden}')
|
|
123
|
+
return 1
|
|
124
|
+
|
|
125
|
+
if opts.delete:
|
|
126
|
+
outp.printf(f'...deleting user: {opts.username}')
|
|
127
|
+
await cell.delUser(useriden)
|
|
128
|
+
return 0
|
|
129
|
+
|
|
130
|
+
if opts.admin is not None:
|
|
131
|
+
admin = s_common.yamlloads(opts.admin)
|
|
132
|
+
mesg = f'...setting admin: {opts.admin}'
|
|
133
|
+
if opts.gate:
|
|
134
|
+
mesg += f' on gate {opts.gate}'
|
|
135
|
+
|
|
136
|
+
outp.printf(mesg)
|
|
137
|
+
await cell.setUserAdmin(useriden, admin, gateiden=opts.gate)
|
|
138
|
+
|
|
139
|
+
if opts.locked is not None:
|
|
140
|
+
locked = s_common.yamlloads(opts.locked)
|
|
141
|
+
outp.printf(f'...setting locked: {opts.locked}')
|
|
142
|
+
await cell.setUserLocked(useriden, locked)
|
|
143
|
+
|
|
144
|
+
if opts.passwd is not None:
|
|
145
|
+
outp.printf(f'...setting passwd: {opts.passwd}')
|
|
146
|
+
await cell.setUserPasswd(useriden, opts.passwd)
|
|
147
|
+
|
|
148
|
+
if opts.email is not None:
|
|
149
|
+
outp.printf(f'...setting email: {opts.email}')
|
|
150
|
+
await cell.setUserEmail(useriden, opts.email)
|
|
151
|
+
|
|
152
|
+
for role in grants:
|
|
153
|
+
rolename = role.get('name')
|
|
154
|
+
outp.printf(f'...granting role: {rolename}')
|
|
155
|
+
await cell.addUserRole(useriden, role.get('iden'))
|
|
156
|
+
|
|
157
|
+
for role in revokes:
|
|
158
|
+
rolename = role.get('name')
|
|
159
|
+
outp.printf(f'...revoking role: {rolename}')
|
|
160
|
+
await cell.delUserRole(useriden, role.get('iden'))
|
|
161
|
+
|
|
162
|
+
for allow in opts.allow:
|
|
163
|
+
perm = allow.lower().split('.')
|
|
164
|
+
mesg = f'...adding allow rule: {allow}'
|
|
165
|
+
if opts.gate:
|
|
166
|
+
mesg += f' on gate {opts.gate}'
|
|
167
|
+
|
|
168
|
+
outp.printf(mesg)
|
|
169
|
+
if not await cell.isUserAllowed(useriden, perm, gateiden=opts.gate):
|
|
170
|
+
await cell.addUserRule(useriden, (True, perm), indx=0, gateiden=opts.gate)
|
|
171
|
+
|
|
172
|
+
for deny in opts.deny:
|
|
173
|
+
perm = deny.lower().split('.')
|
|
174
|
+
mesg = f'...adding deny rule: {deny}'
|
|
175
|
+
if opts.gate:
|
|
176
|
+
mesg += f' on gate {opts.gate}'
|
|
177
|
+
|
|
178
|
+
outp.printf(mesg)
|
|
179
|
+
if await cell.isUserAllowed(useriden, perm, gateiden=opts.gate):
|
|
180
|
+
await cell.addUserRule(useriden, (False, perm), indx=0, gateiden=opts.gate)
|
|
181
|
+
return 0
|
|
182
|
+
|
|
183
|
+
if __name__ == '__main__': # pragma: no cover
|
|
184
|
+
s_cmd.exitmain(main)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import synapse.exc as s_exc
|
|
2
|
+
|
|
3
|
+
import synapse.telepath as s_telepath
|
|
4
|
+
|
|
5
|
+
import synapse.lib.cmd as s_cmd
|
|
6
|
+
import synapse.lib.output as s_output
|
|
7
|
+
import synapse.lib.urlhelp as s_urlhelp
|
|
8
|
+
|
|
9
|
+
descr = '''
|
|
10
|
+
Promote a mirror to the leader.
|
|
11
|
+
|
|
12
|
+
Example (being run from a Cortex mirror docker container):
|
|
13
|
+
python -m synapse.tools.service.promote
|
|
14
|
+
'''
|
|
15
|
+
|
|
16
|
+
async def main(argv, outp=s_output.stdout):
|
|
17
|
+
|
|
18
|
+
pars = s_cmd.Parser(prog='synapse.tools.service.promote', outp=outp, description=descr)
|
|
19
|
+
|
|
20
|
+
pars.add_argument('--svcurl', default='cell:///vertex/storage',
|
|
21
|
+
help='The telepath URL of the Synapse service.')
|
|
22
|
+
|
|
23
|
+
pars.add_argument('--failure', default=False, action='store_true',
|
|
24
|
+
help='Promotion is due to leader being offline. Graceful handoff is not possible.')
|
|
25
|
+
|
|
26
|
+
opts = pars.parse_args(argv)
|
|
27
|
+
|
|
28
|
+
async with s_telepath.withTeleEnv():
|
|
29
|
+
|
|
30
|
+
async with await s_telepath.openurl(opts.svcurl) as cell:
|
|
31
|
+
|
|
32
|
+
graceful = not opts.failure
|
|
33
|
+
|
|
34
|
+
outp.printf(f'Promoting to leader: {opts.svcurl}')
|
|
35
|
+
try:
|
|
36
|
+
await cell.promote(graceful=graceful)
|
|
37
|
+
except s_exc.BadState as e:
|
|
38
|
+
mesg = f'Failed to promote service to being a leader; {e.get("mesg")}'
|
|
39
|
+
outp.printf(mesg)
|
|
40
|
+
return 1
|
|
41
|
+
except s_exc.SynErr as e:
|
|
42
|
+
outp.printf(f'Failed to promote service {s_urlhelp.sanitizeUrl(opts.svcurl)}: {e}')
|
|
43
|
+
return 1
|
|
44
|
+
|
|
45
|
+
return 0
|
|
46
|
+
|
|
47
|
+
if __name__ == '__main__': # pragma: no cover
|
|
48
|
+
s_cmd.exitmain(main)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import synapse.telepath as s_telepath
|
|
2
|
+
|
|
3
|
+
import synapse.lib.cmd as s_cmd
|
|
4
|
+
import synapse.lib.output as s_output
|
|
5
|
+
import synapse.lib.urlhelp as s_urlhelp
|
|
6
|
+
|
|
7
|
+
descr = '''
|
|
8
|
+
List or execute reload subsystems on a Synapse service.
|
|
9
|
+
'''
|
|
10
|
+
|
|
11
|
+
async def main(argv, outp=s_output.stdout):
|
|
12
|
+
|
|
13
|
+
pars = getArgParser(outp)
|
|
14
|
+
opts = pars.parse_args(argv)
|
|
15
|
+
|
|
16
|
+
async with s_telepath.withTeleEnv():
|
|
17
|
+
|
|
18
|
+
async with await s_telepath.openurl(opts.svcurl) as cell:
|
|
19
|
+
|
|
20
|
+
if opts.cmd == 'list':
|
|
21
|
+
names = await cell.getReloadableSystems()
|
|
22
|
+
if names:
|
|
23
|
+
outp.printf(f'Cell at {s_urlhelp.sanitizeUrl(opts.svcurl)} has the following reload subsystems:')
|
|
24
|
+
for name in names:
|
|
25
|
+
outp.printf(name)
|
|
26
|
+
else:
|
|
27
|
+
outp.printf(f'Cell at {s_urlhelp.sanitizeUrl(opts.svcurl)} has no registered reload subsystems.')
|
|
28
|
+
|
|
29
|
+
if opts.cmd == 'reload':
|
|
30
|
+
outp.printf(f'Reloading cell at {s_urlhelp.sanitizeUrl(opts.svcurl)}')
|
|
31
|
+
try:
|
|
32
|
+
ret = await cell.reload(subsystem=opts.name)
|
|
33
|
+
except Exception as e:
|
|
34
|
+
outp.printf(f'Error reloading cell: {e}')
|
|
35
|
+
return 1
|
|
36
|
+
|
|
37
|
+
if not ret:
|
|
38
|
+
outp.printf('No subsystems reloaded.')
|
|
39
|
+
else:
|
|
40
|
+
outp.printf(f'{"Name:".ljust(40)}{"Result:".ljust(10)}Value:')
|
|
41
|
+
for name, (isok, valu) in ret.items():
|
|
42
|
+
if isok:
|
|
43
|
+
mesg = str(valu)
|
|
44
|
+
result = 'Success'
|
|
45
|
+
else:
|
|
46
|
+
mesg = valu[1].get('mesg')
|
|
47
|
+
if mesg is None:
|
|
48
|
+
mesg = valu[0]
|
|
49
|
+
result = 'Failed'
|
|
50
|
+
|
|
51
|
+
outp.printf(f'{name.ljust(40)}{result.ljust(10)}{mesg}')
|
|
52
|
+
return 0
|
|
53
|
+
|
|
54
|
+
def getArgParser(outp):
|
|
55
|
+
pars = s_cmd.Parser(prog='synapse.tools.service.reload', outp=outp, description=descr)
|
|
56
|
+
pars.add_argument('--svcurl', default='cell:///vertex/storage', help='The telepath URL of the Synapse service.')
|
|
57
|
+
|
|
58
|
+
subpars = pars.add_subparsers(required=True,
|
|
59
|
+
title='subcommands',
|
|
60
|
+
dest='cmd',)
|
|
61
|
+
pars_list = subpars.add_parser('list', help='List subsystems which can be reloaded.')
|
|
62
|
+
reld_list = subpars.add_parser('reload', help='Reload registered subsystems.')
|
|
63
|
+
reld_list.add_argument('-n', '--name', type=str, help='Name of a subsystem to reload.')
|
|
64
|
+
|
|
65
|
+
return pars
|
|
66
|
+
|
|
67
|
+
if __name__ == '__main__': # pragma: no cover
|
|
68
|
+
s_cmd.exitmain(main)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import synapse.exc as s_exc
|
|
2
|
+
import synapse.telepath as s_telepath
|
|
3
|
+
|
|
4
|
+
import synapse.lib.cmd as s_cmd
|
|
5
|
+
import synapse.lib.output as s_output
|
|
6
|
+
|
|
7
|
+
desc = '''
|
|
8
|
+
Initiate a graceful shutdown of a service.
|
|
9
|
+
|
|
10
|
+
This tool is designed to put the service into a state where
|
|
11
|
+
any non-background tasks will be allowed to complete while ensuring
|
|
12
|
+
no new tasks are created. Without a timeout, it can block forever if
|
|
13
|
+
tasks do not exit.
|
|
14
|
+
|
|
15
|
+
The command exits with code 0 if the graceful shutdown was successful and
|
|
16
|
+
exit code 1 if a timeout was specified and was hit. Upon hitting the timeout
|
|
17
|
+
the system resumes normal operation.
|
|
18
|
+
|
|
19
|
+
NOTE: This will also demote the service if run on a leader with mirrors.
|
|
20
|
+
'''
|
|
21
|
+
|
|
22
|
+
async def main(argv, outp=s_output.stdout):
|
|
23
|
+
|
|
24
|
+
pars = s_cmd.Parser(prog='synapse.tools.service.shutdown', outp=outp, description=desc)
|
|
25
|
+
|
|
26
|
+
pars.add_argument('--url', default='cell:///vertex/storage',
|
|
27
|
+
help='The telepath URL to connect to the service.')
|
|
28
|
+
|
|
29
|
+
pars.add_argument('--timeout', default=None, type=int,
|
|
30
|
+
help='An optional timeout in seconds. If timeout is reached, the shutdown is aborted.')
|
|
31
|
+
|
|
32
|
+
opts = pars.parse_args(argv)
|
|
33
|
+
|
|
34
|
+
async with s_telepath.withTeleEnv():
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
|
|
38
|
+
async with await s_telepath.openurl(opts.url) as proxy:
|
|
39
|
+
|
|
40
|
+
if await proxy.shutdown(timeout=opts.timeout):
|
|
41
|
+
return 0
|
|
42
|
+
|
|
43
|
+
return 1
|
|
44
|
+
|
|
45
|
+
except Exception as e: # pragma: no cover
|
|
46
|
+
text = s_exc.reprexc(e)
|
|
47
|
+
outp.printf(f'Error while attempting graceful shutdown: {text}')
|
|
48
|
+
return 1
|
|
49
|
+
|
|
50
|
+
if __name__ == '__main__': # pragma: no cover
|
|
51
|
+
s_cmd.exitmain(main)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import synapse.exc as s_exc
|
|
3
|
+
import synapse.telepath as s_telepath
|
|
4
|
+
|
|
5
|
+
import synapse.lib.cmd as s_cmd
|
|
6
|
+
import synapse.lib.output as s_output
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
desc = '''
|
|
11
|
+
Command line tool to freeze/resume service operations to allow
|
|
12
|
+
system admins to generate a transactionally consistent volume
|
|
13
|
+
snapshot using 3rd party tools.
|
|
14
|
+
|
|
15
|
+
The use pattern should be::
|
|
16
|
+
|
|
17
|
+
python -m synapse.tools.service.snapshot freeze
|
|
18
|
+
|
|
19
|
+
<generate volume snapshot using 3rd party tools>
|
|
20
|
+
|
|
21
|
+
python -m synapse.tools.service.snapshot resume
|
|
22
|
+
|
|
23
|
+
The tool will set the process exit code to 0 on success.
|
|
24
|
+
'''
|
|
25
|
+
|
|
26
|
+
async def main(argv, outp=s_output.stdout):
|
|
27
|
+
|
|
28
|
+
pars = s_cmd.Parser(prog='synapse.tools.service.snapshot', outp=outp, description=desc)
|
|
29
|
+
|
|
30
|
+
subs = pars.add_subparsers(required=True, title='commands', dest='cmd')
|
|
31
|
+
|
|
32
|
+
freeze = subs.add_parser('freeze', help='Suspend edits and sync changes to disk.')
|
|
33
|
+
freeze.add_argument('--timeout', type=int, default=120,
|
|
34
|
+
help='Maximum time to wait for the nexus lock.')
|
|
35
|
+
|
|
36
|
+
freeze.add_argument('--svcurl', default='cell:///vertex/storage',
|
|
37
|
+
help='The telepath URL of the Synapse service.')
|
|
38
|
+
|
|
39
|
+
resume = subs.add_parser('resume', help='Resume edits and continue normal operation.')
|
|
40
|
+
resume.add_argument('--svcurl', default='cell:///vertex/storage',
|
|
41
|
+
help='The telepath URL of the Synapse service.')
|
|
42
|
+
|
|
43
|
+
opts = pars.parse_args(argv)
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
async with s_telepath.withTeleEnv():
|
|
47
|
+
|
|
48
|
+
async with await s_telepath.openurl(opts.svcurl) as proxy:
|
|
49
|
+
|
|
50
|
+
if opts.cmd == 'freeze':
|
|
51
|
+
await proxy.freeze(timeout=opts.timeout)
|
|
52
|
+
return 0
|
|
53
|
+
|
|
54
|
+
if opts.cmd == 'resume':
|
|
55
|
+
await proxy.resume()
|
|
56
|
+
return 0
|
|
57
|
+
|
|
58
|
+
except s_exc.SynErr as e:
|
|
59
|
+
mesg = e.errinfo.get('mesg')
|
|
60
|
+
outp.printf(f'ERROR {e.__class__.__name__}: {mesg}')
|
|
61
|
+
return 1
|
|
62
|
+
|
|
63
|
+
if __name__ == '__main__': # pragma: no cover
|
|
64
|
+
s_cmd.exitmain(main)
|