moat-kv 0.70.24__py3-none-any.whl → 0.71.0__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 (74) hide show
  1. build/lib/moat/kv/_cfg.yaml +2 -6
  2. build/lib/moat/kv/backend/mqtt.py +0 -3
  3. ci/rtd-requirements.txt +4 -0
  4. ci/test-requirements.txt +7 -0
  5. ci/travis.sh +96 -0
  6. debian/.gitignore +7 -0
  7. debian/changelog +1435 -0
  8. debian/control +43 -0
  9. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml +2 -6
  10. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py +0 -3
  11. debian/moat-kv.postinst +3 -0
  12. debian/rules +20 -0
  13. debian/source/format +1 -0
  14. debian/watch +4 -0
  15. docs/Makefile +20 -0
  16. docs/make.bat +36 -0
  17. docs/source/TODO.rst +61 -0
  18. docs/source/_static/.gitkeep +0 -0
  19. docs/source/acls.rst +80 -0
  20. docs/source/auth.rst +84 -0
  21. docs/source/client_protocol.rst +456 -0
  22. docs/source/code.rst +341 -0
  23. docs/source/command_line.rst +1187 -0
  24. docs/source/common_protocol.rst +47 -0
  25. docs/source/debugging.rst +70 -0
  26. docs/source/extend.rst +37 -0
  27. docs/source/history.rst +36 -0
  28. docs/source/index.rst +75 -0
  29. docs/source/model.rst +54 -0
  30. docs/source/overview.rst +83 -0
  31. docs/source/related.rst +89 -0
  32. docs/source/server_protocol.rst +450 -0
  33. docs/source/startup.rst +31 -0
  34. docs/source/translator.rst +244 -0
  35. docs/source/tutorial.rst +711 -0
  36. docs/source/v3.rst +168 -0
  37. examples/code/transform.scale.yml +21 -0
  38. examples/code/transform.switch.yml +82 -0
  39. examples/code/transform.timeslot.yml +63 -0
  40. moat/kv/_cfg.yaml +2 -6
  41. moat/kv/backend/mqtt.py +0 -3
  42. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/METADATA +2 -5
  43. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/RECORD +68 -17
  44. scripts/current +15 -0
  45. scripts/env +8 -0
  46. scripts/init +39 -0
  47. scripts/recover +17 -0
  48. scripts/rotate +33 -0
  49. scripts/run +29 -0
  50. scripts/run-all +10 -0
  51. scripts/run-any +10 -0
  52. scripts/run-single +15 -0
  53. scripts/success +4 -0
  54. systemd/moat-kv-recover.service +21 -0
  55. systemd/moat-kv-rotate.service +20 -0
  56. systemd/moat-kv-rotate.timer +10 -0
  57. systemd/moat-kv-run-all.service +26 -0
  58. systemd/moat-kv-run-all@.service +25 -0
  59. systemd/moat-kv-run-any.service +26 -0
  60. systemd/moat-kv-run-any@.service +25 -0
  61. systemd/moat-kv-run-single.service +26 -0
  62. systemd/moat-kv-run-single@.service +25 -0
  63. systemd/moat-kv.service +27 -0
  64. systemd/postinst +7 -0
  65. systemd/sysusers +3 -0
  66. build/lib/moat/kv/backend/serf.py +0 -45
  67. build/lib/moat/kv/mock/serf.py +0 -250
  68. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/serf.py +0 -45
  69. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/serf.py +0 -250
  70. moat/kv/backend/serf.py +0 -45
  71. moat/kv/mock/serf.py +0 -250
  72. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/WHEEL +0 -0
  73. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/licenses/LICENSE.txt +0 -0
  74. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/top_level.txt +0 -0
docs/source/v3.rst ADDED
@@ -0,0 +1,168 @@
1
+ =================
2
+ MoaT-KV Version 3
3
+ =================
4
+
5
+ +++++++++
6
+ Rationale
7
+ +++++++++
8
+
9
+ The V2 servers worked, for the most part, but they had a couple of problems.
10
+
11
+ * sometimes there are strange deadlocks
12
+
13
+ * msgpack isn't that widely supported compared to CBOR
14
+
15
+ * the initial client/server negotiation isn't versioned
16
+
17
+ * the sync protocol is somewhat overengineered
18
+
19
+ * speed of updates is limited by the client>server>MQTT>server>client
20
+ chain; two possibly-high-load servers in between cause too much delay
21
+
22
+ * Messages tended to be more verbose than necessary
23
+
24
+ ++++++++++++++++++
25
+ V3 design overview
26
+ ++++++++++++++++++
27
+
28
+ Server start
29
+ ++++++++++++
30
+
31
+ * connect to MQTT, listen to all MoaT messages,
32
+ update internal state as messages come in
33
+
34
+ * ask for a server link on the Join/Actor topic
35
+
36
+ * load the local backup if present
37
+
38
+ * fetch full tree from designated server is replied
39
+
40
+ * merge data
41
+
42
+ * Join actor topic
43
+
44
+
45
+ Client connection setup A
46
+ +++++++++++++++++++++++++
47
+
48
+ * Client connects to MQTT and sends Query message
49
+ * Designated server replies with connection data
50
+ * Client connects to server
51
+
52
+ * Server greets client
53
+ * Client authenticates
54
+ * Server sends MQTT connection information
55
+ * Client connects to MQTT and sends Birth message
56
+ * Server sees the client's message and sends ACK to the client
57
+
58
+ Client connection setup B
59
+ +++++++++++++++++++++++++
60
+
61
+ This method is slower; it can be used when the configured server doesn't work.
62
+
63
+ * Client connects to MQTT and sends Query message
64
+ * Designated server sends connection data
65
+
66
+ Reading initial data
67
+ ++++++++++++++++++++
68
+
69
+ * Client subscribes to MQTT topic
70
+ * Client requests initial data from server
71
+ * Server sends data, advises client that no data exist, or tells the client
72
+ that MQTT uses retaining (if so, which codec to use)
73
+
74
+ Updates
75
+ +++++++
76
+
77
+ The most notable pain point of the old design is the speed of updates.
78
+ Thus in V3 all updates will be MQTT messages.
79
+
80
+ This section does not apply if the MQTT server retains the data.
81
+
82
+ MoaT update messages are CBOR maps. Keys are small integers for message brevity and
83
+ decode speed.
84
+
85
+ * 0: tock
86
+
87
+ The system-wide update counter. May be missing.
88
+
89
+ * 1: value
90
+
91
+ Contents: Whatever is CBOR-encodeable. A missing value means that the
92
+ object shall be deleted.
93
+
94
+ * 2: tick.
95
+
96
+ Update tracker. This is a ``((name, seq, counter), …)`` list of tuples.
97
+
98
+ * name
99
+ The server's name
100
+
101
+ * seq
102
+ Client connection. Zero is reserved for server-generated content.
103
+
104
+ * counter
105
+ A per-client update counter, managed by the client. Must start at 1 and
106
+ increment in steps of 1, in order to detect skipped updates.
107
+
108
+
109
+ The server sees the update and sends an ACK message to the client, assuming
110
+ that there was no conflict.
111
+
112
+
113
+ Skipped updates
114
+ +++++++++++++++
115
+
116
+ Servers listen to all messages. If there's a gap in a client's sequence
117
+ numbers, the server will ask it to repeat the message.
118
+
119
+
120
+ Update conflict resolution
121
+ ++++++++++++++++++++++++++
122
+
123
+ If a client sends a message which the server determines
124
+
125
+
126
+ MQTT topics
127
+ +++++++++++
128
+
129
+ All are under a common configured prefix, the default is "moat/main".
130
+
131
+ svc/act
132
+ -------
133
+
134
+ The Actor topic for server identification.
135
+
136
+ The transmitted value contains the server's name, host and port.
137
+
138
+
139
+ svc/query
140
+ ---------
141
+
142
+ Connect requests from clients.
143
+
144
+ svc/server
145
+ ----------
146
+
147
+ Reply queue for messages to ``svc/query``. Contains the server value as
148
+ above.
149
+
150
+
151
+ d/*
152
+ ---
153
+
154
+ Update messages.
155
+
156
+ Topic translation
157
+ +++++++++++++++++
158
+
159
+ Topics are encoded like MoaT paths, except for these differences:
160
+
161
+ * The path separator is ``/`` instead of ``.``
162
+ * Slashes are escaped as ``:_``.
163
+ * Spaces in paths are never escaped: that would collide with the previous rule
164
+ * Dots are not escaped, obviously.
165
+ * `None` is encoded as "$NULL" when it's a top-level element.
166
+ * The sequence ``:.`` is used to shield both wildcards and strings with a
167
+ leading ``$`` character. It translates back to an empty string, not a
168
+ dot, and may be treated as an illegal sequence otherwise.
@@ -0,0 +1,21 @@
1
+ code: |
2
+ await _self.watch(src, fetch=False)
3
+ async for msg in _info:
4
+ if isinstance(msg, _cls.ChangeMsg):
5
+ try:
6
+ val = msg.value * factor + offset
7
+ except AttributeError:
8
+ continue
9
+ await _client.set(dst, value=val, idem=False)
10
+ info: Apply factor+offset
11
+ is_async: true
12
+ vars:
13
+ - src
14
+ - dst
15
+ - factor
16
+ - offset
17
+
18
+ # Whenever the value at 'src', changes, this code multiplies it by
19
+ # 'factor', adds 'offset', and writes it to 'dst'.
20
+ #
21
+ # This takes ~0.025 seconds, end-to-end, on a Raspberry Pi 3.
@@ -0,0 +1,82 @@
1
+ code: |
2
+ await _self.watch(src, fetch=False)
3
+ inv = high < low
4
+ if inv:
5
+ high,low = low,high
6
+ res = await _client.get(flip)
7
+ if "value" in res:
8
+ is_high = res.value != inv
9
+ else:
10
+ await _client.set(flip, value=inv)
11
+ is_high = False
12
+
13
+ async for msg in _info:
14
+ if isinstance(msg, _cls.ChangeMsg):
15
+ try:
16
+ val = msg.value
17
+ except AttributeError:
18
+ continue
19
+ if is_high and val < low:
20
+ is_high = False
21
+ await _client.set(flip, value=inv)
22
+ elif not is_high and val > high:
23
+ is_high = True
24
+ await _client.set(flip, value=not inv)
25
+ else:
26
+ if is_high:
27
+ val += high-low
28
+ await _client.set(dst, value=val)
29
+ info: Switch input between triggers
30
+ is_async: true
31
+ vars:
32
+ - src
33
+ - dst
34
+ - flip
35
+ - high
36
+ - low
37
+
38
+ # Consider this simple hook-up of a photoresistor:
39
+ #
40
+ # +5V --- PHOTO --+-- R1 --+-- R2 --- GND
41
+ # | |
42
+ # sensor port
43
+ #
44
+ # The port is a pull-down output: thus, this setup switches resistance
45
+ # between R1 and R1+R2, which allows us to measure the wide range of
46
+ # resistance which a typical photoresistor has, without requiring more
47
+ # fancy circuitry.
48
+ # ‹low› and ‹high› need to be calculated so that
49
+ #
50
+ # * when the photoresistor's resistance is such that the voltage at the
51
+ # sensor is at ‹high›, switching on the port will set the voltage to
52
+ # ‹low›, so you don't get a break in the brightness curve
53
+ # * the rate of change is roughly equal, so you don't get a kink in that
54
+ # curve.
55
+ #
56
+ # These conditions are satisfied when R(photo) = √(R1*(R1+R2)).
57
+ # So if R1=100Ω and R2=10kΩ, R(photo) at the switching point would be 1005Ω,
58
+ # thus you can calculate V(high) as 4.55 Volt and V(low) as 0.45 Volt.
59
+ #
60
+ # The actual choice of resistors is up to you and depends on the
61
+ # photoresistor's behavior in "interesting" lighting conditions. In general
62
+ # you'd want a high-resolution capture of the values at both ends of the
63
+ # range. Thus the above resistor values are sensible if the photoresistor
64
+ # is at 5kΩ when the light gets bright enough to read the newspaper (you
65
+ # want to capture as many nuances of the dark phase as possible), and at
66
+ # 50Ω on a bright summer day just as a cloud has obscured the sun.
67
+ # Or something like that.
68
+ #
69
+ # 'src' is the path which the sensor value is written to. Presumably it's
70
+ # polled periodically.
71
+ #
72
+ # 'dst' is the entry which receives the adjusted value.
73
+ #
74
+ # 'flip' is the entry which corresponds to the port. It receives a `bool`
75
+ # value (`False` on startup).
76
+ #
77
+ # 'low' and 'high' are the threshold values. If 'low' is greater than
78
+ # 'high', the port is inverted (i.e. it's set to `True` on startup).
79
+ #
80
+ # When a ‹src› update causes the port to be inverted, writing to ‹dst› is
81
+ # skipped: if the new value is close to the threshold, the delay doesn't
82
+ # matter much, and if it's not the value would be too inaccurate.
@@ -0,0 +1,63 @@
1
+ code: |
2
+ last_val = None
3
+ this_val = None
4
+ timer = None
5
+ await _client.set(dst, value=0, idem=True)
6
+ await _self.watch(src, fetch=True)
7
+
8
+ async for msg in _info:
9
+ if isinstance(msg, _cls.ChangeMsg):
10
+ try:
11
+ val = msg.value
12
+ except AttributeError:
13
+ continue
14
+ if last_val is None:
15
+ last_val = val
16
+ this_val = val
17
+ continue
18
+ this_val = val
19
+ delta = this_val - last_val
20
+ if delta > 0 and timer is None:
21
+ # fire an immediate update at first change
22
+ await _client.set(dst, value=delta*factor, idem=(delta == 0))
23
+ timer = await _self.timer(seconds)
24
+ elif delta < 0:
25
+ # wraparound or whatever
26
+ last_val = this_val
27
+ if timer is not None:
28
+ await timer.cancel()
29
+ timer = None
30
+ elif isinstance(msg, _cls.TimerMsg):
31
+ delta = this_val - last_val
32
+ if delta >= 0:
33
+ await _client.set(dst, value=delta*factor, idem=(delta == 0))
34
+ if delta > 0:
35
+ await timer.run(seconds)
36
+ else:
37
+ timer = None
38
+ last_val = this_val
39
+ info: generate timeslots for counter deltas
40
+ is_async: true
41
+ vars:
42
+ - src
43
+ - dst
44
+ - seconds
45
+ - factor
46
+
47
+ # This code converts a randomly-updating counter into one that carries a
48
+ # defined meaning.
49
+ #
50
+ # Consider a rain meter. The counter triggers whenever the meter's counter
51
+ # triggers possibly aggregated so that you don't get more than one update
52
+ # every ten seconds even if it's raining buckets.
53
+ #
54
+ # However, in your display you want the rate of rain over, say, the last
55
+ # minute, so you can show some approximation of "how much rain is there
56
+ # right now".
57
+ #
58
+ # This code sends an initial update immediately so that receiving code sees
59
+ # some value > 0 ASAP, then another update every ‹seconds›.
60
+ #
61
+ # Updates are scaled by ‹factor› so you can translate the counter's output
62
+ # to something understandable like "how many mm of water would there be on
63
+ # the ground if this amount of rain continued for an hour".
moat/kv/_cfg.yaml CHANGED
@@ -26,7 +26,6 @@ runner: # for moat.kv.runner.RunnerRoot
26
26
  state: !P :.moat.kv.state"
27
27
 
28
28
  name: "run"
29
- # Serf event name, suffixed by subpath
30
29
 
31
30
  start_delay: 1
32
31
  # time to wait between job starts. Not optional.
@@ -56,9 +55,6 @@ server:
56
55
  # default
57
56
  mqtt:
58
57
  uri: "mqtt://localhost:1883"
59
- serf:
60
- host: "localhost"
61
- port: 7373
62
58
 
63
59
  # event message path/topic prefix
64
60
  root: !P moat.kv
@@ -79,10 +75,10 @@ server:
79
75
  ping:
80
76
  cycle: 10
81
77
  gap: 2
82
- # asyncserf.Actor config timing for server sync
78
+ # asyncactor config timing for server sync
83
79
  # ping also controls minimum server startup time
84
80
  delete:
85
- # asyncserf.Actor config timing for deletion
81
+ # asyncactor config timing for deletion
86
82
  cycle: 100
87
83
  gap: 10
88
84
  version: 1
moat/kv/backend/mqtt.py CHANGED
@@ -11,9 +11,6 @@ from . import Backend
11
11
 
12
12
  logger = logging.getLogger(__name__)
13
13
 
14
- # Simply setting connect=asyncserf.serf_client interferes with mocking
15
- # when testing.
16
-
17
14
 
18
15
  class MqttMessage:
19
16
  def __init__(self, topic, payload):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moat-kv
3
- Version: 0.70.24
3
+ Version: 0.71.0
4
4
  Summary: A distributed no-master key-value store
5
5
  Author-email: Matthias Urlichs <matthias@urlichs.de>
6
6
  Project-URL: homepage, https://m-o-a-t.org
@@ -25,7 +25,6 @@ Requires-Dist: trio>=0.22
25
25
  Requires-Dist: anyio>=4
26
26
  Requires-Dist: range_set>=0.2
27
27
  Requires-Dist: attrs>=22
28
- Requires-Dist: asyncserf>=0.16
29
28
  Requires-Dist: asyncactor>=0.24
30
29
  Requires-Dist: asyncscope>=0.10.4
31
30
  Requires-Dist: jsonschema>=2.5
@@ -34,11 +33,9 @@ Requires-Dist: PyNaCl>=1.3
34
33
  Requires-Dist: moat-lib-diffiehellman~=0.13.4
35
34
  Requires-Dist: psutil
36
35
  Requires-Dist: simpleeval>=0.9.10
37
- Requires-Dist: moat-mqtt~=0.42.3
36
+ Requires-Dist: moat-mqtt~=0.42.4
38
37
  Requires-Dist: moat-util~=0.56.4
39
38
  Requires-Dist: exceptiongroup; python_version < "3.11"
40
- Provides-Extra: dev
41
- Requires-Dist: moat-src>=0.5.0; extra == "dev"
42
39
  Dynamic: license-file
43
40
 
44
41
  =======
@@ -1,7 +1,7 @@
1
1
  build/lib/docs/source/conf.py,sha256=v4cO_xK-WpfHeOCQ4RaeHFk8vwBM7Gg3sw6DgGLmpCc,6072
2
2
  build/lib/examples/pathify.py,sha256=cq2j7Nqhl3jmoNZ6l8wMj4j7DkHMxyB7-oTOrCZA0xQ,1128
3
3
  build/lib/moat/kv/__init__.py,sha256=TO2TyH5Focv78vDDqtiN1vZVLsVihrOqvHBAlLIgVRA,508
4
- build/lib/moat/kv/_cfg.yaml,sha256=fYMbr4A3-WuXxhqwJIY3AL_t2L_kKrlgJWU2bHry7t8,2249
4
+ build/lib/moat/kv/_cfg.yaml,sha256=HMyyiInthAOme_j9ydpfMzSvWVn_wgpNFAFyhpOCsuo,2153
5
5
  build/lib/moat/kv/_main.py,sha256=SgI4ef8AQDOC4N4pLRiyaiSiFIzN-J337WIcuC7DPOY,2234
6
6
  build/lib/moat/kv/client.py,sha256=c8YV0sjpO2XYpNE-fep7fDO2kgsNdShZxgCjohy23CY,34549
7
7
  build/lib/moat/kv/code.py,sha256=gM7WNsjCfukr7h2fKm1U3zMHN5Wj-_hgy5U817LP9qE,6427
@@ -21,8 +21,7 @@ build/lib/moat/kv/auth/_test.py,sha256=ZaMpMf2CTJ6sdGyENUhdWAY5TLC-kBtszM3dFQbyu
21
21
  build/lib/moat/kv/auth/password.py,sha256=DQG2BnNEoQ0H-znkHJx0G9-bcdWwg3IgqojcAHhKIsQ,6307
22
22
  build/lib/moat/kv/auth/root.py,sha256=lW-_hgQp3ZIzAAe4iBl0rdMU-pFuHIC6ObA3rdFXxkk,1303
23
23
  build/lib/moat/kv/backend/__init__.py,sha256=f5nIOWD2zml2YiaBNXtEOzC7SEGgwDFJMB8YzRISJ0A,1689
24
- build/lib/moat/kv/backend/mqtt.py,sha256=0pRGXZmTuVl5cNwzo5ypc_84Zuzyu0aEtRGTbK8gjYk,2095
25
- build/lib/moat/kv/backend/serf.py,sha256=i4u7V6h8SPO3XmP76DiARnFLC4M67xnQEX5-9SgbwtU,1295
24
+ build/lib/moat/kv/backend/mqtt.py,sha256=XUwMR8RPzq6EPLub0cy7YzXTS1CkfBZFtZ4W9GTcQBo,2007
26
25
  build/lib/moat/kv/command/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8
27
26
  build/lib/moat/kv/command/acl.py,sha256=wSdlzKBjWIFX3IxCdLcG3ZqjvtX8KPtqe38ibyU2VDo,4665
28
27
  build/lib/moat/kv/command/auth.py,sha256=vP22ZIBMjRdUxN4_ELKiDgIE5ZqdMxs1ky1WDVUx50M,7149
@@ -38,14 +37,22 @@ build/lib/moat/kv/command/type.py,sha256=JN0_Abb5wR4UJH5zHnVZgT93NJRYY6qpRD_ZQT1
38
37
  build/lib/moat/kv/command/dump/__init__.py,sha256=L05R6W9eDzUDAr7UhfEo1lZR-UB0qYUUf-5dRHC-p-0,4000
39
38
  build/lib/moat/kv/mock/__init__.py,sha256=HW6YAwo_OBVRmTeRCc-ZoUHB7-D78cEONlcb5vACdIE,2760
40
39
  build/lib/moat/kv/mock/mqtt.py,sha256=b9pzbwQBmTX2eSiSgNO7nh2-7l8-0TT8n2GxinQ-1l0,5213
41
- build/lib/moat/kv/mock/serf.py,sha256=cuNT3jEXg3eq7Gs2R6734_gdWeyzZryZoT78MtemDH4,7611
42
40
  build/lib/moat/kv/mock/tracer.py,sha256=qLEIn9gdlYUypyRYD8O8SbM8ye8XR4xtBl3otP6uNLs,2058
43
41
  build/lib/moat/kv/obj/__init__.py,sha256=yeiZ6bWM8XhK28ruqX7RmpPhytYXlOJPRw_hsWbvExk,19800
44
42
  build/lib/moat/kv/obj/command.py,sha256=QQiOhPtlGV07kuutV0KowmC2HiXhmIFUktofqlRg1GA,7446
43
+ ci/rtd-requirements.txt,sha256=q_4dVDUIuXYxY3nN9_NCKYUiBpktQFouyqfmCANc1W4,123
44
+ ci/test-requirements.txt,sha256=ABIHUDbtJ3hpVgItYyHuFbh9UKuRMYmkILROxc1ygmk,74
45
+ ci/travis.sh,sha256=CZiQZUebAmYYH3DUOArik0ktJCG8Q0DE7lb0D-porDo,3335
46
+ debian/.gitignore,sha256=hecgAHAGCwd3DkI44GQT08cmd8DaCcz-zOQuINQ7ZKs,97
47
+ debian/changelog,sha256=lcGqGWXCsqfuc6LC02cFdiK7c9RD4p9tNMSqOttB81s,32353
48
+ debian/control,sha256=a5aeNf2U0O9kAZjh28-g0-HuJsYksxPWTgVNZ5kW2VY,1441
49
+ debian/moat-kv.postinst,sha256=2z322zcHXXTX0lXcOUn9DBnVPNO4f_d8nsfxuhNpfHY,33
50
+ debian/rules,sha256=bOC4tJvuLUgFaQmBu_zxcjtJGn01HkZKhctnDoqT6WY,461
51
+ debian/watch,sha256=O8zhQHur_qoHyzVIewbea-dfUSkJmCmV7P6PzZFPkR4,191
45
52
  debian/moat-kv/usr/lib/python3/dist-packages/docs/source/conf.py,sha256=v4cO_xK-WpfHeOCQ4RaeHFk8vwBM7Gg3sw6DgGLmpCc,6072
46
53
  debian/moat-kv/usr/lib/python3/dist-packages/examples/pathify.py,sha256=cq2j7Nqhl3jmoNZ6l8wMj4j7DkHMxyB7-oTOrCZA0xQ,1128
47
54
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/__init__.py,sha256=TO2TyH5Focv78vDDqtiN1vZVLsVihrOqvHBAlLIgVRA,508
48
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml,sha256=fYMbr4A3-WuXxhqwJIY3AL_t2L_kKrlgJWU2bHry7t8,2249
55
+ debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml,sha256=HMyyiInthAOme_j9ydpfMzSvWVn_wgpNFAFyhpOCsuo,2153
49
56
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_main.py,sha256=SgI4ef8AQDOC4N4pLRiyaiSiFIzN-J337WIcuC7DPOY,2234
50
57
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/client.py,sha256=c8YV0sjpO2XYpNE-fep7fDO2kgsNdShZxgCjohy23CY,34549
51
58
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/code.py,sha256=gM7WNsjCfukr7h2fKm1U3zMHN5Wj-_hgy5U817LP9qE,6427
@@ -65,8 +72,7 @@ debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/_test.py,sha256=ZaMpMf
65
72
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/password.py,sha256=DQG2BnNEoQ0H-znkHJx0G9-bcdWwg3IgqojcAHhKIsQ,6307
66
73
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/root.py,sha256=lW-_hgQp3ZIzAAe4iBl0rdMU-pFuHIC6ObA3rdFXxkk,1303
67
74
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/__init__.py,sha256=f5nIOWD2zml2YiaBNXtEOzC7SEGgwDFJMB8YzRISJ0A,1689
68
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py,sha256=0pRGXZmTuVl5cNwzo5ypc_84Zuzyu0aEtRGTbK8gjYk,2095
69
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/serf.py,sha256=i4u7V6h8SPO3XmP76DiARnFLC4M67xnQEX5-9SgbwtU,1295
75
+ debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py,sha256=XUwMR8RPzq6EPLub0cy7YzXTS1CkfBZFtZ4W9GTcQBo,2007
70
76
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8
71
77
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/acl.py,sha256=wSdlzKBjWIFX3IxCdLcG3ZqjvtX8KPtqe38ibyU2VDo,4665
72
78
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/auth.py,sha256=vP22ZIBMjRdUxN4_ELKiDgIE5ZqdMxs1ky1WDVUx50M,7149
@@ -82,14 +88,39 @@ debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/type.py,sha256=JN0_
82
88
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/dump/__init__.py,sha256=L05R6W9eDzUDAr7UhfEo1lZR-UB0qYUUf-5dRHC-p-0,4000
83
89
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/__init__.py,sha256=HW6YAwo_OBVRmTeRCc-ZoUHB7-D78cEONlcb5vACdIE,2760
84
90
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/mqtt.py,sha256=b9pzbwQBmTX2eSiSgNO7nh2-7l8-0TT8n2GxinQ-1l0,5213
85
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/serf.py,sha256=cuNT3jEXg3eq7Gs2R6734_gdWeyzZryZoT78MtemDH4,7611
86
91
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/tracer.py,sha256=qLEIn9gdlYUypyRYD8O8SbM8ye8XR4xtBl3otP6uNLs,2058
87
92
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/__init__.py,sha256=yeiZ6bWM8XhK28ruqX7RmpPhytYXlOJPRw_hsWbvExk,19800
88
93
  debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/command.py,sha256=QQiOhPtlGV07kuutV0KowmC2HiXhmIFUktofqlRg1GA,7446
94
+ debian/source/format,sha256=G-cIDXLmtWbfPiNs4sVe_fu7j6HJctgl5bZy_4dzvho,12
95
+ docs/Makefile,sha256=g6jq_WYItszUyPzdvzs04ZgPOGXE_THsm2zAbvVUMnU,609
96
+ docs/make.bat,sha256=tZwnc3a-ozijIP3JTHDoSdNFMwXwrELNhOCFMBxB7K0,779
97
+ docs/source/TODO.rst,sha256=87ZE4VAEzSgYXr2BvUCnMFYa1TSNAr3nPiZNt0b6B5Y,1921
98
+ docs/source/acls.rst,sha256=qAG7SrTnBJv2IIS36FC74ubt0FJQ5rZBwd8yXuYQZd0,2018
99
+ docs/source/auth.rst,sha256=9-4se2vH-kbB86BiUMfafTXNtmHrPHH9nZDujRxw0ww,2603
100
+ docs/source/client_protocol.rst,sha256=X_EMTbWRXBotwAPDRCDeZUEBaK2OXul8t_PV0BiC1Gs,14094
101
+ docs/source/code.rst,sha256=ihHRtzpeEWGhioCUssakSrbkB7V2heA0Qca4RKcAv00,10371
102
+ docs/source/command_line.rst,sha256=jBK1-5Kc_ySTiIhVNK7W2Ffdf21MszCLFo3Z_aC04Kw,29241
103
+ docs/source/common_protocol.rst,sha256=8TT3OMZc0nX8wRSMg6gQk88OwQ2TekWTjcJVK4ymdfc,1281
89
104
  docs/source/conf.py,sha256=v4cO_xK-WpfHeOCQ4RaeHFk8vwBM7Gg3sw6DgGLmpCc,6072
105
+ docs/source/debugging.rst,sha256=1wZIQGsHjMoLCKAK0TPlvAtxqMU4UyvHa6tUhXN4_eE,2188
106
+ docs/source/extend.rst,sha256=UjLPvKaod14mEbi20r2Qtx2ROZmsu2cWRAENMfFhlD4,1402
107
+ docs/source/history.rst,sha256=ba0qchAJyGI0exigWDrhYT26KfxjIYEnf8hFcr_XKJ8,868
108
+ docs/source/index.rst,sha256=8-oMWmXV6aXzUT6JK-ghYZMphDu98srReAVkj4IV3jU,1866
109
+ docs/source/model.rst,sha256=8yZfsmoOikxDw-0d82ArPg3MP-XzLWou0lfw8Ry8C0Q,1622
110
+ docs/source/overview.rst,sha256=-PdRj09LBJP-in5zWMO66OXTCu04tZvuReyeOlHP64c,3409
111
+ docs/source/related.rst,sha256=CvlTLgsnnha3646NMhH7Kg9KW1WZr0xQistU903C9Gc,2749
112
+ docs/source/server_protocol.rst,sha256=l9uG0yKOSmr9X7JuokWYbOauGUyp-FZYnbP73UTHNgk,16180
113
+ docs/source/startup.rst,sha256=vx2_zvNrKHiRaYK5GIfzzJ1SmtMtVJ8yXJHfRhfxWuI,1085
114
+ docs/source/translator.rst,sha256=b1x0H_8E9abPEA-dBk656wWQpnioGpNmJKfbZz1XnnU,7513
115
+ docs/source/tutorial.rst,sha256=uoAZR44f6734Y7N9TYLai6-SEF0iPZRfJ8iXHn0yeKA,22429
116
+ docs/source/v3.rst,sha256=EQf1i4LJe7cSyWCgi_gLYAJjBmeF1KJ5yaKRzpB5psc,3960
117
+ docs/source/_static/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
118
  examples/pathify.py,sha256=cq2j7Nqhl3jmoNZ6l8wMj4j7DkHMxyB7-oTOrCZA0xQ,1128
119
+ examples/code/transform.scale.yml,sha256=aim0aTXvbrGfkNsZ6WM5JUHTXfZdGCvKPGhq-8O9IQo,550
120
+ examples/code/transform.switch.yml,sha256=NUoO3241TtL-L-orMR0a3i2I0ZJLpgbz_TVXT07NocE,3033
121
+ examples/code/transform.timeslot.yml,sha256=9SSOEE77rT2iveH0UZLrmv9VeUJkAgb5k5bGV5C8WAk,2142
91
122
  moat/kv/__init__.py,sha256=TO2TyH5Focv78vDDqtiN1vZVLsVihrOqvHBAlLIgVRA,508
92
- moat/kv/_cfg.yaml,sha256=fYMbr4A3-WuXxhqwJIY3AL_t2L_kKrlgJWU2bHry7t8,2249
123
+ moat/kv/_cfg.yaml,sha256=HMyyiInthAOme_j9ydpfMzSvWVn_wgpNFAFyhpOCsuo,2153
93
124
  moat/kv/_main.py,sha256=SgI4ef8AQDOC4N4pLRiyaiSiFIzN-J337WIcuC7DPOY,2234
94
125
  moat/kv/client.py,sha256=c8YV0sjpO2XYpNE-fep7fDO2kgsNdShZxgCjohy23CY,34549
95
126
  moat/kv/code.py,sha256=gM7WNsjCfukr7h2fKm1U3zMHN5Wj-_hgy5U817LP9qE,6427
@@ -109,8 +140,7 @@ moat/kv/auth/_test.py,sha256=ZaMpMf2CTJ6sdGyENUhdWAY5TLC-kBtszM3dFQbyuWA,4342
109
140
  moat/kv/auth/password.py,sha256=DQG2BnNEoQ0H-znkHJx0G9-bcdWwg3IgqojcAHhKIsQ,6307
110
141
  moat/kv/auth/root.py,sha256=lW-_hgQp3ZIzAAe4iBl0rdMU-pFuHIC6ObA3rdFXxkk,1303
111
142
  moat/kv/backend/__init__.py,sha256=f5nIOWD2zml2YiaBNXtEOzC7SEGgwDFJMB8YzRISJ0A,1689
112
- moat/kv/backend/mqtt.py,sha256=0pRGXZmTuVl5cNwzo5ypc_84Zuzyu0aEtRGTbK8gjYk,2095
113
- moat/kv/backend/serf.py,sha256=i4u7V6h8SPO3XmP76DiARnFLC4M67xnQEX5-9SgbwtU,1295
143
+ moat/kv/backend/mqtt.py,sha256=XUwMR8RPzq6EPLub0cy7YzXTS1CkfBZFtZ4W9GTcQBo,2007
114
144
  moat/kv/command/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8
115
145
  moat/kv/command/acl.py,sha256=wSdlzKBjWIFX3IxCdLcG3ZqjvtX8KPtqe38ibyU2VDo,4665
116
146
  moat/kv/command/auth.py,sha256=vP22ZIBMjRdUxN4_ELKiDgIE5ZqdMxs1ky1WDVUx50M,7149
@@ -126,12 +156,33 @@ moat/kv/command/type.py,sha256=JN0_Abb5wR4UJH5zHnVZgT93NJRYY6qpRD_ZQT13u4k,6226
126
156
  moat/kv/command/dump/__init__.py,sha256=L05R6W9eDzUDAr7UhfEo1lZR-UB0qYUUf-5dRHC-p-0,4000
127
157
  moat/kv/mock/__init__.py,sha256=HW6YAwo_OBVRmTeRCc-ZoUHB7-D78cEONlcb5vACdIE,2760
128
158
  moat/kv/mock/mqtt.py,sha256=b9pzbwQBmTX2eSiSgNO7nh2-7l8-0TT8n2GxinQ-1l0,5213
129
- moat/kv/mock/serf.py,sha256=cuNT3jEXg3eq7Gs2R6734_gdWeyzZryZoT78MtemDH4,7611
130
159
  moat/kv/mock/tracer.py,sha256=qLEIn9gdlYUypyRYD8O8SbM8ye8XR4xtBl3otP6uNLs,2058
131
160
  moat/kv/obj/__init__.py,sha256=yeiZ6bWM8XhK28ruqX7RmpPhytYXlOJPRw_hsWbvExk,19800
132
161
  moat/kv/obj/command.py,sha256=QQiOhPtlGV07kuutV0KowmC2HiXhmIFUktofqlRg1GA,7446
133
- moat_kv-0.70.24.dist-info/licenses/LICENSE.txt,sha256=L5vKJLVOg5t0CEEPpW9-O_0vzbP0PEjEF06tLvnIDuk,541
134
- moat_kv-0.70.24.dist-info/METADATA,sha256=fvQT4BFn3YX4hgGBlXxeNwglvnfWcu8vnxaEopeuHS8,3370
135
- moat_kv-0.70.24.dist-info/WHEEL,sha256=xcaH6rP_nCxh1LBIPM7Q0uOnzSGjsIye-Q44j_zbzw8,104
136
- moat_kv-0.70.24.dist-info/top_level.txt,sha256=LyFVSz3-SU-7B8r2qZ3ODVF_QvXqE08qepkD1rfQLk4,56
137
- moat_kv-0.70.24.dist-info/RECORD,,
162
+ moat_kv-0.71.0.dist-info/licenses/LICENSE.txt,sha256=L5vKJLVOg5t0CEEPpW9-O_0vzbP0PEjEF06tLvnIDuk,541
163
+ scripts/current,sha256=91NXrtN9AWtOdwGZs-yTaAgU_EKF4xXPo9Dvr9E3BkA,374
164
+ scripts/env,sha256=Le76hZQSvDrNiFfhCzK0PDe4STLOdIpMcsQTYgk74Qs,113
165
+ scripts/init,sha256=gvezyZaPG-6RJ5nLC9Wc0kR_tZaiJAjLpJfRVnyfFik,1071
166
+ scripts/recover,sha256=dBuIN9v6yJ_dffVAsax8AfnD9oRfQHi0U8kk5w1ReH4,332
167
+ scripts/rotate,sha256=zoBI7A5hN54TNgC0FYIMGusHmqe1LcICNyhkukL7eYs,837
168
+ scripts/run,sha256=Zbh5Qa5oYmn-fMpg_qUaPVbJrpDx4ht0rjKSm0eQt7E,795
169
+ scripts/run-all,sha256=GlheLEcCxQejv0cPmPPHSpXvK0ZcGQ_XDbt7W-ouPTM,220
170
+ scripts/run-any,sha256=y0y1Lk7ppUnOtiYrcAWHBetsW77nZEmlx-S2A7mhxYg,210
171
+ scripts/run-single,sha256=GmGi5Nu0uUmcs5PJiEBaEbz3O7k1-669nUoAX-Bj2KQ,316
172
+ scripts/success,sha256=KCkdAPsgiEiUBcEgluKJFcB5fGk6VEv0Uo8FP9frKLA,33
173
+ systemd/moat-kv-recover.service,sha256=zqqDEBW21iQ8O2tBdiAMEUoGdgt1ZLLzmhToIAq76Ew,355
174
+ systemd/moat-kv-rotate.service,sha256=BFhLT6FIwk0w0q9AH_mfKS9S1T0wcjr-8oH01bn2LPI,355
175
+ systemd/moat-kv-rotate.timer,sha256=vQ6oVU4KhvD9q-90y8GUil1ewIv0ld4jULrLelHJ-2I,161
176
+ systemd/moat-kv-run-all.service,sha256=D34_d8o3qmNAGEtlqpdx4oaU2jUd7h3qypkjQMcGgHE,428
177
+ systemd/moat-kv-run-all@.service,sha256=-00TrYu3-3k01spmb0_FfbZFBkzguOMcp3LUyjiesfI,397
178
+ systemd/moat-kv-run-any.service,sha256=kINPhW7CIQCIuMsuKnXTkzOw9dTZ-ujxpJWWQPcC-Ic,428
179
+ systemd/moat-kv-run-any@.service,sha256=EQXBp1P-MgAzGD1wr2RXgBDkz_zx1MGcz6FMf09GCwU,397
180
+ systemd/moat-kv-run-single.service,sha256=ASLd9fH-tY8ZnAsuPmNxiuKaVfGzLC56EJU39UtlEgk,436
181
+ systemd/moat-kv-run-single@.service,sha256=uhy3Pl9ojm4vJhYVP1CxYdM_e-vtIq0q6b-oWjrdABQ,402
182
+ systemd/moat-kv.service,sha256=g9BtStXpKDQ0o3Ivgw5t9s5KintzXabJIR6FvL-nJnQ,502
183
+ systemd/postinst,sha256=INv8dSI8KT5VKX9Fr8uN0l6IbAO3Bi28aTQTgfQArL8,198
184
+ systemd/sysusers,sha256=swfLW1o9tZ8i1d8KL5JP75R1p7DVMekLX0r-YTNPZlY,78
185
+ moat_kv-0.71.0.dist-info/METADATA,sha256=sRDrUCQS6Kf6Z6xmDdcXPzbNFv3wougCrsWIRcrqu2c,3271
186
+ moat_kv-0.71.0.dist-info/WHEEL,sha256=xcaH6rP_nCxh1LBIPM7Q0uOnzSGjsIye-Q44j_zbzw8,104
187
+ moat_kv-0.71.0.dist-info/top_level.txt,sha256=LyFVSz3-SU-7B8r2qZ3ODVF_QvXqE08qepkD1rfQLk4,56
188
+ moat_kv-0.71.0.dist-info/RECORD,,
scripts/current ADDED
@@ -0,0 +1,15 @@
1
+ #!/bin/sh
2
+ set -ex
3
+
4
+ # This script takes the most-current state files and writes them to the
5
+ # named file.
6
+
7
+ test -n "$1"
8
+ F="$(python3 -c "import sys; from os.path import abspath; print(abspath(sys.argv[1]))" "$1")"
9
+
10
+ mkdir -p "$DEST"
11
+ cd "$DEST"
12
+ d=$(find . -name 0.dkv -size +1c -print | sort -r | head -1)
13
+ cd $(dirname "$d")
14
+
15
+ ls | grep '\.dkv$' | sort -n | xargs cat > "$TEMP"
scripts/env ADDED
@@ -0,0 +1,8 @@
1
+ # shell
2
+
3
+ PATH=/usr/bin:/bin
4
+ DEST=/var/lib/moat/kv/
5
+ DATE="%Y-%m-%d-%H"
6
+ MODE=hybrid
7
+ TEMP=/tmp/moat.kv.current.dkv
8
+
scripts/init ADDED
@@ -0,0 +1,39 @@
1
+ #!/bin/sh
2
+ set -ex
3
+
4
+ # This script sets up an initial MoaT-KV master.
5
+ systemd-sysusers --no-pager /usr/lib/sysusers.d/moat-kv.conf
6
+
7
+ . /usr/lib/moat/kv/env
8
+
9
+ mkdir -p /etc/moat
10
+ test -f /etc/moat/kv.env || touch /etc/moat/kv.env
11
+ grep -qs '^MODE=' /etc/moat/kv.env || echo MODE=hybrid >>/etc/moat/kv.env
12
+ grep -qs '^NAME=' /etc/moat/kv.env || echo NAME=$(hostname) >>/etc/moat/kv.env
13
+ grep -qs '^LOCAL=' /etc/moat/kv.env || echo LOCAL=no >>/etc/moat/kv.env
14
+
15
+ . /etc/moat/kv.env
16
+
17
+ if test "$MODE" != "slave" ; then
18
+ mkdir -p "$DEST"
19
+ cd "$DEST"
20
+ d="$(find . -name 0.dkv -size +1c | sort | head -1)"
21
+ if test -n "$d" ; then
22
+ d="$(dirname "$d")"
23
+ else
24
+ d="$(date -d 2019-01-01 +"$DATE")"
25
+ mkdir -p "$d"
26
+ fi
27
+ cd $d
28
+
29
+ if test ! -s "0.dkv" ; then
30
+ moat kv dump init $NAME 0.dkv
31
+ chown -R MoaT-KV:MoaT "$DEST"
32
+ fi
33
+ fi
34
+
35
+ if test "$(moat util cfg kv.conn.host)" = "127.0.0.1" ; then
36
+ systemctl enable moat-kv.service
37
+ systemctl enable moat-kv-rotate.timer || true # may be masked
38
+ systemctl restart moat-kv.service &
39
+ fi
scripts/recover ADDED
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+ set -ex
3
+
4
+ # This script tries to recover from hybrid mode start failure
5
+ # by re-starting in master mode.
6
+
7
+ if ! test "$MODE" = hybrid ; then
8
+ echo "Not hybrid mode. Not restarting." >&2
9
+ exit 1
10
+ fi
11
+
12
+ if test -f "$TEMP" ; then
13
+ echo "$TEMP exists, not restarting" >&2
14
+ exit 1
15
+ fi
16
+ /usr/lib/moat/kv/current "$TEMP"
17
+
scripts/rotate ADDED
@@ -0,0 +1,33 @@
1
+ #!/bin/sh
2
+ set -ex
3
+
4
+ # This script tells MoaT-KV to continue with the next log file.
5
+ # By default it writes a full dump daily.
6
+
7
+ cd "$DEST"
8
+ D=$(date +"$DATE")
9
+ test -d $D || mkdir -p $D
10
+ cd $D
11
+
12
+ x=$(ls|sort -rn|head -1)
13
+ if test -n "$x" ; then
14
+ x=$(expr $(basename $x .dkv) + 1)
15
+ I="-i"
16
+ else
17
+ x=0
18
+ I=""
19
+ fi
20
+
21
+ export PYTHONPATH
22
+ moat -c /etc/moat/moat.cfg kv client log dest $I "$DEST/$D/$x.dkv"
23
+ if test $x -eq 0 ; then
24
+ # Now, delete some old backups
25
+ cd "$DEST"
26
+
27
+ # delete hourly after ten days but keep the day's first backup
28
+ find . -maxdepth 1 ! -name \*-00 -mtime +10 -print0|xargs -0r rm -rf
29
+ # delete daily after 45 days but keep the month's first backup
30
+ find . -maxdepth 1 ! -name \*01-00 -mtime +45 -print0|xargs -0r rm -rf
31
+ # delete monthly (i.e. the rest) after a year or so
32
+ find . -maxdepth 1 -mtime +400 -print0|xargs -0r rm -rf
33
+ fi