moat-kv 0.70.22__py3-none-any.whl → 0.70.23__py3-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.
Files changed (52) hide show
  1. moat/kv/__init__.py +1 -0
  2. moat/kv/_cfg.yaml +97 -0
  3. moat/kv/_main.py +6 -9
  4. moat/kv/client.py +34 -50
  5. moat/kv/code.py +10 -3
  6. moat/kv/codec.py +1 -0
  7. moat/kv/config.py +2 -0
  8. moat/kv/data.py +8 -7
  9. moat/kv/errors.py +17 -9
  10. moat/kv/exceptions.py +1 -7
  11. moat/kv/model.py +16 -24
  12. moat/kv/runner.py +38 -35
  13. moat/kv/server.py +86 -90
  14. moat/kv/types.py +5 -8
  15. {moat_kv-0.70.22.dist-info → moat_kv-0.70.23.dist-info}/METADATA +15 -18
  16. moat_kv-0.70.23.dist-info/RECORD +19 -0
  17. {moat_kv-0.70.22.dist-info → moat_kv-0.70.23.dist-info}/WHEEL +1 -1
  18. moat_kv-0.70.23.dist-info/licenses/LICENSE.txt +14 -0
  19. moat/kv/_config.yaml +0 -98
  20. moat/kv/actor/__init__.py +0 -97
  21. moat/kv/actor/deletor.py +0 -137
  22. moat/kv/auth/__init__.py +0 -446
  23. moat/kv/auth/_test.py +0 -172
  24. moat/kv/auth/password.py +0 -232
  25. moat/kv/auth/root.py +0 -56
  26. moat/kv/backend/__init__.py +0 -66
  27. moat/kv/backend/mqtt.py +0 -74
  28. moat/kv/backend/serf.py +0 -44
  29. moat/kv/command/__init__.py +0 -1
  30. moat/kv/command/acl.py +0 -174
  31. moat/kv/command/auth.py +0 -258
  32. moat/kv/command/code.py +0 -306
  33. moat/kv/command/codec.py +0 -190
  34. moat/kv/command/data.py +0 -274
  35. moat/kv/command/dump/__init__.py +0 -141
  36. moat/kv/command/error.py +0 -156
  37. moat/kv/command/internal.py +0 -257
  38. moat/kv/command/job.py +0 -438
  39. moat/kv/command/log.py +0 -52
  40. moat/kv/command/server.py +0 -115
  41. moat/kv/command/type.py +0 -203
  42. moat/kv/mock/__init__.py +0 -97
  43. moat/kv/mock/mqtt.py +0 -164
  44. moat/kv/mock/serf.py +0 -253
  45. moat/kv/mock/tracer.py +0 -65
  46. moat/kv/obj/__init__.py +0 -636
  47. moat/kv/obj/command.py +0 -246
  48. moat_kv-0.70.22.dist-info/LICENSE +0 -3
  49. moat_kv-0.70.22.dist-info/LICENSE.APACHE2 +0 -202
  50. moat_kv-0.70.22.dist-info/LICENSE.MIT +0 -20
  51. moat_kv-0.70.22.dist-info/RECORD +0 -49
  52. {moat_kv-0.70.22.dist-info → moat_kv-0.70.23.dist-info}/top_level.txt +0 -0
moat/kv/command/error.py DELETED
@@ -1,156 +0,0 @@
1
- # command line interface
2
-
3
- import sys
4
-
5
- import asyncclick as click
6
- from moat.util import P, Path, yprint
7
-
8
- from moat.kv.data import add_dates
9
- from moat.kv.errors import ErrorRoot
10
-
11
-
12
- @click.group() # pylint: disable=undefined-variable
13
- @click.pass_obj
14
- async def cli(obj):
15
- """Manage error records in MoaT-KV."""
16
- obj.err = await ErrorRoot.as_handler(obj.client)
17
-
18
-
19
- @cli.command()
20
- @click.option("-s", "--subsys", help="Subsystem to access")
21
- @click.argument("path", nargs=1)
22
- @click.pass_obj
23
- async def resolve(obj, path, subsys):
24
- """
25
- Mark an error as resolved.
26
- """
27
- path = P(path)
28
- if subsys:
29
- e = obj.err.get_error_record(subsys, path)
30
- else:
31
- e = obj.err.follow(path)
32
- if e.resolved:
33
- print("Already resolved.", file=sys.stderr)
34
- return
35
- await e.resolve()
36
-
37
-
38
- @cli.command()
39
- @click.option("-n", "--node", help="add details from this node")
40
- @click.option(
41
- "-s", "--subsystem", "subsys", help="only show errors from this subsystem"
42
- )
43
- @click.option("-r", "--resolved", is_flag=True, help="only resolved errors")
44
- @click.option(
45
- "-v", "--verbose", count=True, help="add per-node details (-vv for traces)"
46
- )
47
- @click.option("-a", "--all-errors", is_flag=True, help="add details from all nodes")
48
- @click.option(
49
- "-d", "--as-dict", default=None, help="Dump a list of all open (or resolved) error."
50
- )
51
- @click.option("-p", "--path", default=":", help="only show errors below this subpath")
52
- @click.pass_obj
53
- async def dump(obj, as_dict, path, node, all_errors, verbose, resolved, subsys):
54
- """Dump error entries."""
55
- path = P(path)
56
- path_ = obj.cfg["errors"].prefix
57
- d = 2
58
-
59
- async def one(r):
60
- nonlocal y
61
- val = r.value
62
- if subsys and val.get("subsystem", "") != subsys:
63
- return
64
- if path and val.get("path", ())[: len(path)] != path:
65
- return
66
-
67
- if not all_errors and bool(val.get("resolved", False)) != resolved:
68
- return
69
-
70
- add_dates(val)
71
- try:
72
- rp = val.path
73
- if as_dict:
74
- del val.path
75
- elif not isinstance(rp, Path):
76
- rp = Path.build(rp)
77
- except AttributeError:
78
- rp = Path("incomplete") + r.path
79
- if not as_dict:
80
- val.path = rp
81
- if rp[: len(path)] != path:
82
- return
83
- rp = rp[len(path) :]
84
- if node is None:
85
- val.syspath = r.path
86
- else:
87
- val.syspath = Path(node) + r.path
88
-
89
- rn = {}
90
-
91
- def disp(rr):
92
- if node and rr.path[-1] != node:
93
- return
94
- val = rr.value
95
- add_dates(val)
96
- if verbose < 2:
97
- rr.value.pop("trace", None)
98
- rn[rr.path[-1]] = rr if obj.meta else rr.value
99
-
100
- if verbose:
101
- rs = await obj.client._request(
102
- action="get_tree",
103
- min_depth=1,
104
- max_depth=1,
105
- path=path_ + r.path[-2:],
106
- iter=True,
107
- nchain=3 if obj.meta else 0,
108
- )
109
- async for rr in rs:
110
- disp(rr)
111
-
112
- elif node:
113
- rs = await obj.client.get(path_ + r.path[-2:] | node)
114
- if "value" in rs:
115
- disp(rs)
116
-
117
- if rn:
118
- val["nodes"] = rn
119
-
120
- if as_dict is not None:
121
- yy = y
122
- if subsys is None:
123
- yy = yy.setdefault(val.get("subsystem", "unknown"), {})
124
- for p in rp:
125
- yy = yy.setdefault(p, {})
126
- yy[as_dict] = r if obj.meta else val
127
- else:
128
- yy = r if obj.meta else r.value
129
-
130
- yprint([yy], stream=obj.stdout)
131
- print("---", file=obj.stdout)
132
-
133
- y = {}
134
- res = None
135
-
136
- if node is None and len(path) == 2 and isinstance(path[-1], int): # single error?
137
- r = await obj.client.get(path_ + path, nchain=3 if obj.meta else 0)
138
- # Mangle a few variables so that the output is still OK
139
- r.path = path
140
- node = None
141
-
142
- async def ait(r):
143
- yield r
144
-
145
- res = ait(r)
146
- path = ()
147
-
148
- if res is None:
149
- res = obj.client.get_tree(
150
- path_, min_depth=d, max_depth=d, nchain=3 if obj.meta else 0
151
- )
152
- async for r in res:
153
- await one(r)
154
-
155
- if as_dict is not None:
156
- yprint(y, stream=obj.stdout)
@@ -1,257 +0,0 @@
1
- # command line interface
2
-
3
- from collections.abc import Mapping
4
-
5
- import asyncclick as click
6
- from moat.util import P, PathLongener, yprint
7
- from range_set import RangeSet
8
-
9
-
10
- @click.group(short_help="Control internal state.") # pylint: disable=undefined-variable
11
- async def cli():
12
- """
13
- This subcommand queries and controls the server's internal state.
14
- """
15
- pass
16
-
17
-
18
- @cli.command()
19
- @click.option("-n", "--nodes", is_flag=True, help="Get node status.")
20
- @click.option("-d", "--deleted", is_flag=True, help="Get deletion status.")
21
- @click.option("-m", "--missing", is_flag=True, help="Get missing-node status.")
22
- @click.option(
23
- "-r",
24
- "--remote-missing",
25
- "remote_missing",
26
- is_flag=True,
27
- help="Get remote-missing-node status.",
28
- )
29
- @click.option("-p", "--present", is_flag=True, help="Get known-data status.")
30
- @click.option("-s", "--superseded", is_flag=True, help="Get superseded-data status.")
31
- @click.option("-D", "--debug", is_flag=True, help="Get internal verbosity.")
32
- @click.option("--debugger", is_flag=True, help="Start a remote debugger. DO NOT USE.")
33
- @click.option(
34
- "-k", "--known", hidden=True, is_flag=True, help="Get superseded-data status."
35
- )
36
- @click.option("-a", "--all", is_flag=True, help="All available data.")
37
- @click.pass_obj
38
- async def state(obj, **flags):
39
- """
40
- Dump the server's state.
41
- """
42
- if flags.pop("known", None):
43
- flags["superseded"] = True
44
- if flags.pop("all", None):
45
- flags["superseded"] = True
46
- flags["present"] = True
47
- flags["nodes"] = True
48
- flags["deleted"] = True
49
- flags["missing"] = True
50
- flags["remote_missing"] = True
51
- res = await obj.client._request("get_state", iter=False, **flags)
52
- k = res.pop("known", None)
53
- if k is not None:
54
- res["superseded"] = k
55
- yprint(res, stream=obj.stdout)
56
-
57
-
58
- @cli.command()
59
- @click.option(
60
- "-d", "--deleted", is_flag=True, help="Mark as deleted. Default: superseded"
61
- )
62
- @click.option(
63
- "-n",
64
- "--node",
65
- "source",
66
- default="?",
67
- help="The node this message is faked as being from.",
68
- )
69
- @click.option("-b", "--broadcast", is_flag=True, help="Send to all servers")
70
- @click.argument("node", nargs=1)
71
- @click.argument("items", type=int, nargs=-1)
72
- @click.pass_obj
73
- async def mark(obj, deleted, source, node, items, broadcast):
74
- """
75
- Fix internal state. Use no items to fetch the current list from the
76
- server's ``missing`` state. Use an empty node name to add the whole
77
- list, not just a single node's.
78
-
79
- This is a dangerous command.
80
- """
81
-
82
- k = "deleted" if deleted else "superseded"
83
- if not items:
84
- r = await obj.client._request("get_state", iter=False, missing=True)
85
- r = r["missing"]
86
- if node != "":
87
- r = {node: r[node]}
88
- elif node == "":
89
- raise click.UsageError("You can't do that with an empty node")
90
- else:
91
- r = RangeSet()
92
- for i in items:
93
- r.add(i)
94
- r = {node: r.__getstate__()}
95
-
96
- msg = {k: r, "node": source}
97
-
98
- await obj.client._request("fake_info", iter=False, **msg)
99
- if broadcast:
100
- await obj.client._request("fake_info_send", iter=False, **msg)
101
-
102
- res = await obj.client._request("get_state", iter=False, **{k: True})
103
- yprint(res, stream=obj.stdout)
104
-
105
-
106
- @cli.command(short_help="Manage the Deleter list")
107
- @click.option("-d", "--delete", is_flag=True, help="Remove these nodes")
108
- @click.argument("nodes", nargs=-1)
109
- @click.pass_obj
110
- async def deleter(obj, delete, nodes):
111
- """
112
- Manage the Deleter list
113
-
114
- This is the set of nodes that must be online for removal of deleted
115
- entries from MoaT-KV's data.
116
-
117
- There should be one such node in every possible network partition.
118
- Also, all nodes with permanent storage should be on the list.
119
-
120
- Usage:
121
- - … deleter -- list state
122
- - … deleter NODE… -- add this node
123
- - … deleter -d NODE… -- remove this node
124
- """
125
-
126
- res = await obj.client._request(
127
- action="get_internal",
128
- path=("actor", "del"),
129
- iter=False,
130
- nchain=3 if delete or nodes else 2,
131
- )
132
- val = res.get("value", {})
133
- if isinstance(val, Mapping):
134
- val = val.get("nodes", [])
135
- # else: compatibility, TODO remove
136
- val = set(val)
137
- if delete:
138
- if nodes:
139
- val -= set(nodes)
140
- else:
141
- val = set()
142
- elif nodes:
143
- val |= set(nodes)
144
- else:
145
- yprint(res, stream=obj.stdout)
146
- return
147
-
148
- val = {"nodes": list(val)}
149
- res = await obj.client._request(
150
- action="set_internal",
151
- path=("actor", "del"),
152
- iter=False,
153
- chain=res.chain,
154
- value=val,
155
- )
156
- res.value = val
157
- yprint(res, stream=obj.stdout)
158
-
159
-
160
- @cli.command()
161
- @click.argument("path", nargs=1)
162
- @click.pass_obj
163
- async def dump(obj, path):
164
- """
165
- Dump internal state.
166
-
167
- This displays MoaT-KV's internal state.
168
- """
169
-
170
- path = P(path)
171
- y = {}
172
- pl = PathLongener()
173
- async for r in await obj.client._request(
174
- "get_tree_internal", path=path, iter=True, nchain=0
175
- ):
176
- pl(r)
177
- path = r["path"]
178
- yy = y
179
- for p in path:
180
- yy = yy.setdefault(p, {})
181
- try:
182
- yy["_"] = r["value"]
183
- except KeyError:
184
- pass
185
- yprint(y, stream=obj.stdout)
186
-
187
-
188
- @cli.command()
189
- @click.argument("node", nargs=1)
190
- @click.argument("tick", type=int, nargs=1)
191
- @click.pass_obj
192
- async def get(obj, node, tick):
193
- """
194
- Fetch data by node+tick.
195
-
196
- This looks up internal data.
197
- """
198
-
199
- res = await obj.client._request("get_value", node=node, tick=tick, nchain=99)
200
- if not obj.meta:
201
- res = res.value
202
- yprint(res, stream=obj.stdout)
203
-
204
-
205
- @cli.command()
206
- @click.option("-n", "--num", type=int, help="Return at most this many IDs")
207
- @click.option("-c", "--current", is_flag=True, help="Return only IDs with current data")
208
- @click.option("-C", "--copy", is_flag=True, help="Create an no-op change")
209
- @click.argument("node", nargs=1)
210
- @click.pass_obj
211
- async def enum(obj, node, num, current, copy):
212
- """
213
- List IDs of live data by a specific node.
214
-
215
- Can be used to determine whether a node still has live data,
216
- otherwise it can be deleted.
217
-
218
- If '--current' is set, only the IDs of the entries that have last been
219
- updated by that node are shown. '--copy' rewrites these entries.
220
-
221
- Increase verbosity to also show the oject paths.
222
- """
223
-
224
- res = await obj.client._request("enum_node", node=node, max=num, current=current)
225
- if obj.meta and not copy and obj.debug <= 1:
226
- yprint(res, stream=obj.stdout)
227
- else:
228
- for k in res.result:
229
- if copy or obj.debug > 1:
230
- res = await obj.client._request(
231
- "get_value", node=node, tick=k, nchain=3
232
- )
233
- if obj.debug > 1:
234
- print(k, res.path)
235
- else:
236
- print(k)
237
- if copy and res.chain.node == node:
238
- res = await obj.client.set(
239
- res.path, value=res.value, chain=res.chain
240
- )
241
- else:
242
- print(k)
243
-
244
-
245
- @cli.command()
246
- @click.argument("node", nargs=1)
247
- @click.pass_obj
248
- async def kill(obj, node):
249
- """
250
- Remove a node from the node list.
251
-
252
- This command only works if this node does not have any current data in
253
- the system.
254
- """
255
- res = await obj.client._request("kill_node", node=node)
256
- if obj.meta:
257
- yprint(res, stream=obj.stdout)