antietcd 1.0.2 → 1.0.3
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.
- package/README.md +5 -1
- package/anticli.js +78 -8
- package/etctree.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,8 +48,9 @@ Antietcd doesn't background itself, so use systemd or start-stop-daemon to run i
|
|
|
48
48
|
|
|
49
49
|
```
|
|
50
50
|
node_modules/.bin/anticli [OPTIONS] put <key> [<value>]
|
|
51
|
-
node_modules/.bin/anticli [OPTIONS] get <key> [-p|--prefix] [-v|--print-value-only] [-k|--keys-only]
|
|
51
|
+
node_modules/.bin/anticli [OPTIONS] get <key> [-p|--prefix] [-v|--print-value-only] [-k|--keys-only] [--no-temp]
|
|
52
52
|
node_modules/.bin/anticli [OPTIONS] del <key> [-p|--prefix]
|
|
53
|
+
node_modules/.bin/anticli [OPTIONS] load [--with-lease] < dump.json
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
For `put`, if `<value>` is not specified, it will be read from STDIN.
|
|
@@ -70,6 +71,9 @@ Options:
|
|
|
70
71
|
<dt>--timeout 1000</dt>
|
|
71
72
|
<dd>Specify request timeout in milliseconds</dd>
|
|
72
73
|
|
|
74
|
+
<dt>--json or --write-out=json</dt>
|
|
75
|
+
<dd>Print raw response in JSON</dd>
|
|
76
|
+
|
|
73
77
|
</dl>
|
|
74
78
|
|
|
75
79
|
## Options
|
package/anticli.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// (c) Vitaliy Filippov, 2024
|
|
5
5
|
// License: Mozilla Public License 2.0 or Vitastor Network Public License 1.1
|
|
6
6
|
|
|
7
|
+
const fs = require('fs');
|
|
7
8
|
const fsp = require('fs').promises;
|
|
8
9
|
const http = require('http');
|
|
9
10
|
const https = require('https');
|
|
@@ -15,13 +16,14 @@ License: Mozilla Public License 2.0 or Vitastor Network Public License 1.1
|
|
|
15
16
|
Usage:
|
|
16
17
|
|
|
17
18
|
anticli.js [OPTIONS] put <key> [<value>]
|
|
18
|
-
anticli.js [OPTIONS] get <key> [-p|--prefix] [-v|--print-value-only] [-k|--keys-only]
|
|
19
|
+
anticli.js [OPTIONS] get <key> [-p|--prefix] [-v|--print-value-only] [-k|--keys-only] [--no-temp]
|
|
19
20
|
anticli.js [OPTIONS] del <key> [-p|--prefix]
|
|
21
|
+
anticli.js [OPTIONS] load [--with-lease] < dump.json
|
|
20
22
|
|
|
21
23
|
Options:
|
|
22
24
|
|
|
23
25
|
[--endpoints|-e http://node1:2379,http://node2:2379,http://node3:2379]
|
|
24
|
-
[--cert cert.pem] [--key key.pem] [--timeout 1000]
|
|
26
|
+
[--cert cert.pem] [--key key.pem] [--timeout 1000] [--json]
|
|
25
27
|
`;
|
|
26
28
|
|
|
27
29
|
class AntiEtcdCli
|
|
@@ -54,6 +56,19 @@ class AntiEtcdCli
|
|
|
54
56
|
{
|
|
55
57
|
options['keys_only'] = true;
|
|
56
58
|
}
|
|
59
|
+
else if (arg == '--with_lease')
|
|
60
|
+
{
|
|
61
|
+
options['with_lease'] = true;
|
|
62
|
+
}
|
|
63
|
+
else if (arg == '--write_out' && args[i+1] == 'json')
|
|
64
|
+
{
|
|
65
|
+
i++;
|
|
66
|
+
options['json'] = true;
|
|
67
|
+
}
|
|
68
|
+
else if (arg == '--json' || arg == '--write_out=json')
|
|
69
|
+
{
|
|
70
|
+
options['json'] = true;
|
|
71
|
+
}
|
|
57
72
|
else if (arg[0] == '-' && arg[1] !== '-')
|
|
58
73
|
{
|
|
59
74
|
process.stderr.write('Unknown option '+arg);
|
|
@@ -68,9 +83,9 @@ class AntiEtcdCli
|
|
|
68
83
|
cmd.push(arg);
|
|
69
84
|
}
|
|
70
85
|
}
|
|
71
|
-
if (!cmd.length || cmd[0] != 'get' && cmd[0] != 'put' && cmd[0] != 'del')
|
|
86
|
+
if (!cmd.length || cmd[0] != 'get' && cmd[0] != 'put' && cmd[0] != 'del' && cmd[0] != 'load')
|
|
72
87
|
{
|
|
73
|
-
process.stderr.write('Supported commands: get, put, del. Use --help to see details\n');
|
|
88
|
+
process.stderr.write('Supported commands: get, put, del, load. Use --help to see details\n');
|
|
74
89
|
process.exit(1);
|
|
75
90
|
}
|
|
76
91
|
return [ cmd, options ];
|
|
@@ -102,12 +117,51 @@ class AntiEtcdCli
|
|
|
102
117
|
{
|
|
103
118
|
await this.del(cmd.slice(1));
|
|
104
119
|
}
|
|
120
|
+
else if (cmd[0] == 'load')
|
|
121
|
+
{
|
|
122
|
+
await this.load();
|
|
123
|
+
}
|
|
105
124
|
// wait until output is fully flushed
|
|
106
125
|
await new Promise(ok => process.stdout.write('', ok));
|
|
107
126
|
await new Promise(ok => process.stderr.write('', ok));
|
|
108
127
|
process.exit(0);
|
|
109
128
|
}
|
|
110
129
|
|
|
130
|
+
async load()
|
|
131
|
+
{
|
|
132
|
+
const dump = JSON.parse(await new Promise((ok, no) => fs.readFile(0, { encoding: 'utf-8' }, (err, res) => err ? no(err) : ok(res))));
|
|
133
|
+
if (!dump.responses && !dump.kvs)
|
|
134
|
+
{
|
|
135
|
+
console.error('dump should be /kv/txn or /kv/range response in json format');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
const success = [];
|
|
139
|
+
for (const r of (dump.responses
|
|
140
|
+
? dump.responses.map(r => r.response_range).filter(r => r)
|
|
141
|
+
: [ dump ]))
|
|
142
|
+
{
|
|
143
|
+
for (const kv of r.kvs)
|
|
144
|
+
{
|
|
145
|
+
if (kv.value == null)
|
|
146
|
+
{
|
|
147
|
+
console.error('dump should contain values');
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
success.push({ request_put: { key: kv.key, value: kv.value, lease: this.options.with_lease ? kv.lease||undefined : undefined } });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const res = await this.request('/v3/kv/txn', { success });
|
|
154
|
+
if (this.options.json)
|
|
155
|
+
{
|
|
156
|
+
process.stdout.write(JSON.stringify(res));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (res.succeeded)
|
|
160
|
+
{
|
|
161
|
+
process.stdout.write('OK, loaded '+success.length+' values\n');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
111
165
|
async get(keys)
|
|
112
166
|
{
|
|
113
167
|
if (this.options.prefix)
|
|
@@ -116,6 +170,22 @@ class AntiEtcdCli
|
|
|
116
170
|
}
|
|
117
171
|
const txn = { success: keys.map(key => ({ request_range: this.options.prefix ? { key: b64(key+'/'), range_end: b64(key+'0') } : { key: b64(key) } })) };
|
|
118
172
|
const res = await this.request('/v3/kv/txn', txn);
|
|
173
|
+
if (this.options.notemp)
|
|
174
|
+
{
|
|
175
|
+
// Skip temporary values (values with lease)
|
|
176
|
+
for (const r of res.responses||[])
|
|
177
|
+
{
|
|
178
|
+
if (r.response_range)
|
|
179
|
+
{
|
|
180
|
+
r.response_range.kvs = r.response_range.kvs.filter(kv => !kv.lease);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (this.options.json)
|
|
185
|
+
{
|
|
186
|
+
process.stdout.write(JSON.stringify(keys.length == 1 ? res.responses[0].response_range : res));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
119
189
|
for (const r of res.responses||[])
|
|
120
190
|
{
|
|
121
191
|
if (r.response_range)
|
|
@@ -139,7 +209,7 @@ class AntiEtcdCli
|
|
|
139
209
|
{
|
|
140
210
|
if (value === undefined)
|
|
141
211
|
{
|
|
142
|
-
value = await
|
|
212
|
+
value = await new Promise((ok, no) => fs.readFile(0, { encoding: 'utf-8' }, (err, res) => err ? no(err) : ok(res)));
|
|
143
213
|
}
|
|
144
214
|
const res = await this.request('/v3/kv/put', { key: b64(key), value: b64(value) });
|
|
145
215
|
if (res.header)
|
|
@@ -175,18 +245,18 @@ class AntiEtcdCli
|
|
|
175
245
|
{
|
|
176
246
|
if (res.json.error)
|
|
177
247
|
{
|
|
178
|
-
process.stderr.write(cur_url+': '+res.json.error);
|
|
248
|
+
process.stderr.write(cur_url+': '+res.json.error+'\n');
|
|
179
249
|
process.exit(1);
|
|
180
250
|
}
|
|
181
251
|
return res.json;
|
|
182
252
|
}
|
|
183
253
|
if (res.body)
|
|
184
254
|
{
|
|
185
|
-
process.stderr.write(cur_url+': '+res.body);
|
|
255
|
+
process.stderr.write(cur_url+': '+res.body+'\n');
|
|
186
256
|
}
|
|
187
257
|
if (res.error)
|
|
188
258
|
{
|
|
189
|
-
process.stderr.write(cur_url+': '+res.error);
|
|
259
|
+
process.stderr.write(cur_url+': '+res.error+'\n');
|
|
190
260
|
if (!res.response || !res.response.statusCode)
|
|
191
261
|
{
|
|
192
262
|
// This URL is unavailable
|
package/etctree.js
CHANGED
|
@@ -120,7 +120,7 @@ class EtcTree
|
|
|
120
120
|
{
|
|
121
121
|
const key = this.de64(req.key);
|
|
122
122
|
const end = this.de64(req.range_end);
|
|
123
|
-
if (end != null && (key[key.length-1] != '/' || end[end.length-1] != '0' ||
|
|
123
|
+
if (end != null && (key !== '' && end !== '') && (key[key.length-1] != '/' || end[end.length-1] != '0' ||
|
|
124
124
|
end.substr(0, end.length-1) !== key.substr(0, key.length-1)))
|
|
125
125
|
{
|
|
126
126
|
throw new RequestError(501, 'Non-directory range queries are unsupported');
|