kourou 0.25.0 → 0.25.2
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 +8 -3
- package/lib/commands/app/scaffold.js +1 -1
- package/lib/commands/collection/export.d.ts +1 -0
- package/lib/commands/collection/export.js +12 -3
- package/lib/commands/collection/migrate.js +1 -1
- package/lib/commands/index/export.d.ts +1 -0
- package/lib/commands/index/export.js +12 -2
- package/lib/commands/paas/login.js +8 -8
- package/lib/commands/paas/logs.js +36 -16
- package/lib/support/PaasKommand.d.ts +1 -0
- package/lib/support/PaasKommand.js +3 -0
- package/lib/support/dump-collection.js +1 -0
- package/lib/support/kuzzle.js +4 -2
- package/lib/support/restore-collection.js +6 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ $ npm install -g kourou
|
|
|
26
26
|
$ kourou COMMAND
|
|
27
27
|
running command...
|
|
28
28
|
$ kourou (-v|--version|version)
|
|
29
|
-
kourou/0.25.
|
|
29
|
+
kourou/0.25.2 linux-x64 node-v14.20.0
|
|
30
30
|
$ kourou --help [COMMAND]
|
|
31
31
|
USAGE
|
|
32
32
|
$ kourou COMMAND
|
|
@@ -365,7 +365,7 @@ ARGUMENTS
|
|
|
365
365
|
DESTINATION Directory to scaffold the app
|
|
366
366
|
|
|
367
367
|
OPTIONS
|
|
368
|
-
--flavor=flavor [default: generic] Template flavor ("generic", "iot-
|
|
368
|
+
--flavor=flavor [default: generic] Template flavor ("generic", "iot-backend", "iot-console").
|
|
369
369
|
Those can be found here: https://github.com/kuzzleio/project-templates
|
|
370
370
|
|
|
371
371
|
--help show CLI help
|
|
@@ -506,6 +506,9 @@ OPTIONS
|
|
|
506
506
|
--ssl
|
|
507
507
|
Use SSL to connect to Kuzzle
|
|
508
508
|
|
|
509
|
+
--type=type
|
|
510
|
+
[default: all] Type of the export: all, mappings, data
|
|
511
|
+
|
|
509
512
|
--username=username
|
|
510
513
|
[default: anonymous] Kuzzle username (local strategy)
|
|
511
514
|
|
|
@@ -547,7 +550,7 @@ _See code: [src/commands/collection/import.ts](src/commands/collection/import.ts
|
|
|
547
550
|
|
|
548
551
|
## `kourou collection:migrate SCRIPT PATH`
|
|
549
552
|
|
|
550
|
-
Migrate a collection
|
|
553
|
+
Migrate a collection by transforming documents from a dump file and importing them into Kuzzle
|
|
551
554
|
|
|
552
555
|
```
|
|
553
556
|
USAGE
|
|
@@ -938,6 +941,8 @@ OPTIONS
|
|
|
938
941
|
|
|
939
942
|
--ssl Use SSL to connect to Kuzzle
|
|
940
943
|
|
|
944
|
+
--type=type [default: all] Type of the export: all, mappings, data
|
|
945
|
+
|
|
941
946
|
--username=username [default: anonymous] Kuzzle username (local strategy)
|
|
942
947
|
|
|
943
948
|
EXAMPLES
|
|
@@ -35,7 +35,7 @@ AppScaffold.flags = {
|
|
|
35
35
|
help: command_1.flags.help(),
|
|
36
36
|
flavor: command_1.flags.string({
|
|
37
37
|
default: "generic",
|
|
38
|
-
description: `Template flavor ("generic", "iot-
|
|
38
|
+
description: `Template flavor ("generic", "iot-backend", "iot-console").
|
|
39
39
|
Those can be found here: https://github.com/kuzzleio/project-templates`,
|
|
40
40
|
}),
|
|
41
41
|
};
|
|
@@ -22,10 +22,16 @@ class CollectionExport extends common_1.Kommand {
|
|
|
22
22
|
}
|
|
23
23
|
const countAll = await this.sdk.document.count(this.args.index, this.args.collection);
|
|
24
24
|
const count = await this.sdk.document.count(this.args.index, this.args.collection, { query });
|
|
25
|
-
this.logInfo(`Dumping
|
|
25
|
+
this.logInfo(`Dumping collection "${this.args.index}:${this.args.collection}" in ${exportPath} ...`);
|
|
26
26
|
fs_1.default.mkdirSync(exportPath, { recursive: true });
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
if (this.flags.type === "all" || this.flags.type === "mappings") {
|
|
28
|
+
this.logInfo(`Dumping collection mappings ...`);
|
|
29
|
+
await (0, dump_collection_1.dumpCollectionMappings)(this.sdk, this.args.index, this.args.collection, exportPath, this.flags.format);
|
|
30
|
+
}
|
|
31
|
+
if (this.flags.type === "all" || this.flags.type === "data") {
|
|
32
|
+
this.logInfo(`Dumping collection ${count} of ${countAll} documents ...`);
|
|
33
|
+
await (0, dump_collection_1.dumpCollectionData)(this.sdk, this.args.index, this.args.collection, Number(this.flags["batch-size"]), exportPath, query, this.flags.format, fields, this.flags.scrollTTL);
|
|
34
|
+
}
|
|
29
35
|
this.logOk(`Collection ${this.args.index}:${this.args.collection} dumped`);
|
|
30
36
|
}
|
|
31
37
|
}
|
|
@@ -60,6 +66,9 @@ exportable fields in the mapping will be exported.`,
|
|
|
60
66
|
description: `The scroll TTL option to pass to the dump operation (which performs a document.search under the hood),
|
|
61
67
|
expressed in ms format, e.g. '2s', '1m', '3h'.`,
|
|
62
68
|
default: "20s",
|
|
69
|
+
}), type: command_1.flags.string({
|
|
70
|
+
description: "Type of the export: all, mappings, data",
|
|
71
|
+
default: "all",
|
|
63
72
|
}) }, kuzzle_1.kuzzleFlags), { protocol: command_1.flags.string({
|
|
64
73
|
description: "Kuzzle protocol (http or websocket)",
|
|
65
74
|
default: "ws",
|
|
@@ -25,7 +25,7 @@ class CollectionMigrate extends common_1.Kommand {
|
|
|
25
25
|
}
|
|
26
26
|
exports.default = CollectionMigrate;
|
|
27
27
|
CollectionMigrate.keepAuth = true;
|
|
28
|
-
CollectionMigrate.description = "Migrate a collection";
|
|
28
|
+
CollectionMigrate.description = "Migrate a collection by transforming documents from a dump file and importing them into Kuzzle";
|
|
29
29
|
CollectionMigrate.flags = Object.assign(Object.assign({ help: command_1.flags.help({}), "batch-size": command_1.flags.string({
|
|
30
30
|
description: "Maximum batch size (see limits.documentsWriteCount config)",
|
|
31
31
|
default: "200",
|
|
@@ -5,6 +5,7 @@ export default class IndexExport extends Kommand {
|
|
|
5
5
|
static description: string;
|
|
6
6
|
static flags: {
|
|
7
7
|
protocol: flags.IOptionFlag<string>;
|
|
8
|
+
type: flags.IOptionFlag<string>;
|
|
8
9
|
host: flags.IOptionFlag<string>;
|
|
9
10
|
port: flags.IOptionFlag<string>;
|
|
10
11
|
ssl: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
|
|
@@ -19,11 +19,18 @@ class IndexExport extends common_1.Kommand {
|
|
|
19
19
|
const { collections } = await this.sdk.collection.list(this.args.index);
|
|
20
20
|
for (const collection of collections) {
|
|
21
21
|
try {
|
|
22
|
-
if (collection.type
|
|
22
|
+
if (collection.type === "realtime") {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (this.flags.type === "all" || this.flags.type === "mappings") {
|
|
26
|
+
this.logInfo(`Dumping collection "${collection.name}" mappings ...`);
|
|
23
27
|
await (0, dump_collection_1.dumpCollectionMappings)(this.sdk, this.args.index, collection.name, exportPath, this.flags.format);
|
|
28
|
+
}
|
|
29
|
+
if (this.flags.type === "all" || this.flags.type === "data") {
|
|
30
|
+
this.logInfo(`Dumping collection "${collection.name}" documents ...`);
|
|
24
31
|
await (0, dump_collection_1.dumpCollectionData)(this.sdk, this.args.index, collection.name, Number(this.flags["batch-size"]), exportPath, query, this.flags.format, this.flags.scrollTTL);
|
|
25
|
-
cli_ux_1.default.action.stop();
|
|
26
32
|
}
|
|
33
|
+
cli_ux_1.default.action.stop();
|
|
27
34
|
}
|
|
28
35
|
catch (error) {
|
|
29
36
|
this.logKo(`Error when exporting collection "${collection.name}": ${error}`);
|
|
@@ -53,6 +60,9 @@ expressed in ms format, e.g. '2s', '1m', '3h'.`,
|
|
|
53
60
|
}) }, kuzzle_1.kuzzleFlags), { protocol: command_1.flags.string({
|
|
54
61
|
description: "Kuzzle protocol (http or websocket)",
|
|
55
62
|
default: "ws",
|
|
63
|
+
}), type: command_1.flags.string({
|
|
64
|
+
description: "Type of the export: all, mappings, data",
|
|
65
|
+
default: "all",
|
|
56
66
|
}) });
|
|
57
67
|
IndexExport.args = [{ name: "index", description: "Index name", required: true }];
|
|
58
68
|
IndexExport.examples = [
|
|
@@ -20,10 +20,6 @@ class PaasLogin extends PaasKommand_1.PaasKommand {
|
|
|
20
20
|
await this.authenticateNPM(username, password);
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
|
-
if (this.flags.only_npm) {
|
|
24
|
-
await this.authenticateNPM(username, password);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
23
|
await this.initPaasClient({ username, password });
|
|
28
24
|
const apiKey = await this.paas.auth.createApiKey("Kourou PaaS API Key");
|
|
29
25
|
this.createProjectCredentials(apiKey);
|
|
@@ -53,15 +49,19 @@ class PaasLogin extends PaasKommand_1.PaasKommand {
|
|
|
53
49
|
password,
|
|
54
50
|
}),
|
|
55
51
|
};
|
|
56
|
-
const response = await (0, node_fetch_1.default)(`https
|
|
57
|
-
const
|
|
52
|
+
const response = await (0, node_fetch_1.default)(`https://${this.packagesHost}/-/user/org.couchdb.user:${username}`, options);
|
|
53
|
+
const json = await response.json();
|
|
54
|
+
if (response.status !== 201) {
|
|
55
|
+
throw new Error(json.error);
|
|
56
|
+
}
|
|
57
|
+
const { token } = json;
|
|
58
58
|
(0, child_process_1.spawnSync)("npm", [
|
|
59
59
|
"config",
|
|
60
60
|
"set",
|
|
61
61
|
"@kuzzleio:registry",
|
|
62
|
-
|
|
62
|
+
`https://${this.packagesHost}`,
|
|
63
63
|
], { stdio: "inherit" });
|
|
64
|
-
(0, child_process_1.spawnSync)("npm", ["set",
|
|
64
|
+
(0, child_process_1.spawnSync)("npm", ["set", `//${this.packagesHost}/:_authToken`, token], {
|
|
65
65
|
stdio: "inherit",
|
|
66
66
|
});
|
|
67
67
|
}
|
|
@@ -15,7 +15,15 @@ class PaasLogs extends PaasKommand_1.PaasKommand {
|
|
|
15
15
|
/**
|
|
16
16
|
* Allowed colors for pod names.
|
|
17
17
|
*/
|
|
18
|
-
this.allColors = [
|
|
18
|
+
this.allColors = [
|
|
19
|
+
chalk_1.default.red,
|
|
20
|
+
chalk_1.default.green,
|
|
21
|
+
chalk_1.default.yellow,
|
|
22
|
+
chalk_1.default.blue,
|
|
23
|
+
chalk_1.default.magenta,
|
|
24
|
+
chalk_1.default.cyan,
|
|
25
|
+
chalk_1.default.gray,
|
|
26
|
+
];
|
|
19
27
|
/**
|
|
20
28
|
* Available colors for pod names.
|
|
21
29
|
*/
|
|
@@ -34,8 +42,12 @@ class PaasLogs extends PaasKommand_1.PaasKommand {
|
|
|
34
42
|
this.logInfo(`Logged as "${user._id}" for project "${this.flags.project || this.getProject()}"`);
|
|
35
43
|
const separator = "\t";
|
|
36
44
|
// Parse the time arguments
|
|
37
|
-
const since = this.flags.since
|
|
38
|
-
|
|
45
|
+
const since = this.flags.since
|
|
46
|
+
? chrono.parseDate(this.flags.since).toISOString()
|
|
47
|
+
: undefined;
|
|
48
|
+
const until = this.flags.until
|
|
49
|
+
? chrono.parseDate(this.flags.until).toISOString()
|
|
50
|
+
: undefined;
|
|
39
51
|
// Perform the streamed request
|
|
40
52
|
const incomingMessage = await this.paas.queryHttpStream({
|
|
41
53
|
controller: "application",
|
|
@@ -59,18 +71,24 @@ class PaasLogs extends PaasKommand_1.PaasKommand {
|
|
|
59
71
|
// Display the response
|
|
60
72
|
for (var lineStream_1 = (0, tslib_1.__asyncValues)(lineStream), lineStream_1_1; lineStream_1_1 = await lineStream_1.next(), !lineStream_1_1.done;) {
|
|
61
73
|
const line = lineStream_1_1.value;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
try {
|
|
75
|
+
const data = JSON.parse(line);
|
|
76
|
+
// Exclude logs that are empty or that are not from a pod
|
|
77
|
+
if (!data.content || !data.podName) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Get the pod color
|
|
81
|
+
const podColor = this.getPodColor(data.podName);
|
|
82
|
+
// Display the log
|
|
83
|
+
const timestamp = this.flags.timestamp
|
|
84
|
+
? `[${new Date(data.timeStamp).toLocaleString()}] `
|
|
85
|
+
: "";
|
|
86
|
+
const name = podColor(`${data.podName}${separator}`);
|
|
87
|
+
this.log(`${timestamp}${name}| ${data.content}`);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.logKo(`Error while parsing log: ${error} (Received: "${line}")`);
|
|
67
91
|
}
|
|
68
|
-
// Get the pod color
|
|
69
|
-
const podColor = this.getPodColor(data.podName);
|
|
70
|
-
// Display the log
|
|
71
|
-
const timestamp = this.flags.timestamp ? `[${new Date(data.timeStamp).toLocaleString()}] ` : "";
|
|
72
|
-
const name = podColor(`${data.podName}${separator}`);
|
|
73
|
-
this.log(`${timestamp}${name}| ${data.content}`);
|
|
74
92
|
}
|
|
75
93
|
}
|
|
76
94
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
@@ -101,13 +119,15 @@ class PaasLogs extends PaasKommand_1.PaasKommand {
|
|
|
101
119
|
}
|
|
102
120
|
getNumberOfSpaces(names, currentName) {
|
|
103
121
|
const end = 10;
|
|
104
|
-
let max = { name:
|
|
122
|
+
let max = { name: "", length: 0 };
|
|
105
123
|
for (const name of names) {
|
|
106
124
|
if (max.length < name.length) {
|
|
107
125
|
max = { name: name, length: name.length };
|
|
108
126
|
}
|
|
109
127
|
}
|
|
110
|
-
return currentName === max.name
|
|
128
|
+
return currentName === max.name
|
|
129
|
+
? end
|
|
130
|
+
: end + (max.length - currentName.length);
|
|
111
131
|
}
|
|
112
132
|
/**
|
|
113
133
|
* Returns the color to use for a pod name.
|
|
@@ -11,6 +11,7 @@ export declare class PaasKommand extends Kommand {
|
|
|
11
11
|
protected host: string;
|
|
12
12
|
protected port: number;
|
|
13
13
|
protected ssl: any;
|
|
14
|
+
protected packagesHost: string;
|
|
14
15
|
protected paas: KuzzleSDK;
|
|
15
16
|
initPaasClient(credentials: PaaSClientCredentials): Promise<void>;
|
|
16
17
|
fileProjectCredentials(project: string): string;
|
|
@@ -18,6 +18,9 @@ class PaasKommand extends common_1.Kommand {
|
|
|
18
18
|
this.ssl = process.env.KUZZLE_PAAS_SSL
|
|
19
19
|
? JSON.parse(process.env.KUZZLE_PAAS_SSL)
|
|
20
20
|
: true;
|
|
21
|
+
this.packagesHost = process.env.KUZZLE_PAAS_PACKAGES_HOST
|
|
22
|
+
? process.env.KUZZLE_PAAS_PACKAGES_HOST
|
|
23
|
+
: "packages.paas.kuzzle.io";
|
|
21
24
|
// Instantiate a dummy SDK to avoid the this.paas? notation everywhere -_-
|
|
22
25
|
this.paas = new kuzzle_1.KuzzleSDK({});
|
|
23
26
|
}
|
|
@@ -81,6 +81,7 @@ class AbstractDumper {
|
|
|
81
81
|
* @returns a promise resolving when the dump is finished.
|
|
82
82
|
*/
|
|
83
83
|
async dump() {
|
|
84
|
+
fs_1.default.mkdirSync(this.collectionDir, { recursive: true });
|
|
84
85
|
this.filename = path_1.default.join(this.collectionDir, `documents.${this.fileExtension}`);
|
|
85
86
|
this.writeStream = fs_1.default.createWriteStream(this.filename);
|
|
86
87
|
const waitWrite = new Promise((resolve, reject) => this.writeStream ? this.writeStream.on("finish", resolve) : reject());
|
package/lib/support/kuzzle.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.KuzzleSDK = exports.kuzzleFlags = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const http_1 = (0, tslib_1.__importDefault)(require("http"));
|
|
6
|
+
const https_1 = (0, tslib_1.__importDefault)(require("https"));
|
|
6
7
|
const command_1 = require("@oclif/command");
|
|
7
8
|
const kuzzle_sdk_1 = require("kuzzle-sdk");
|
|
8
9
|
const SECOND = 1000;
|
|
@@ -163,14 +164,15 @@ class KuzzleSDK {
|
|
|
163
164
|
const options = {
|
|
164
165
|
method: "POST",
|
|
165
166
|
headers: {
|
|
166
|
-
|
|
167
|
+
Authorization: `Bearer ${this.sdk.jwt}`,
|
|
167
168
|
"Content-Length": Buffer.byteLength(body),
|
|
168
169
|
"Content-Type": "application/json",
|
|
169
170
|
},
|
|
170
171
|
};
|
|
171
172
|
// Send the request
|
|
172
173
|
return new Promise((resolve, reject) => {
|
|
173
|
-
const
|
|
174
|
+
const httpModule = this.ssl ? https_1.default : http_1.default;
|
|
175
|
+
const req = httpModule.request(url, options, (res) => {
|
|
174
176
|
resolve(res);
|
|
175
177
|
});
|
|
176
178
|
req.on("error", reject);
|
|
@@ -6,18 +6,16 @@ const fs_1 = (0, tslib_1.__importDefault)(require("fs"));
|
|
|
6
6
|
const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
|
|
7
7
|
const ndjson_1 = (0, tslib_1.__importDefault)(require("ndjson"));
|
|
8
8
|
function handleError(log, dumpFile, error) {
|
|
9
|
-
if (error.
|
|
9
|
+
if (error.errors) {
|
|
10
10
|
const errorFile = `${dumpFile
|
|
11
11
|
.split(".")
|
|
12
12
|
.slice(0, -1)
|
|
13
13
|
.join(".")}-errors.jsonl`;
|
|
14
14
|
const writeStream = fs_1.default.createWriteStream(errorFile, { flags: "a" });
|
|
15
|
-
const serialize = ndjson_1.default.stringify().pipe(writeStream);
|
|
16
|
-
serialize.on("data", (line) => writeStream.write(line));
|
|
17
15
|
for (const partialError of error.errors) {
|
|
18
|
-
|
|
16
|
+
writeStream.write(JSON.stringify(partialError) + '\n');
|
|
19
17
|
}
|
|
20
|
-
|
|
18
|
+
writeStream.end();
|
|
21
19
|
log(chalk_1.default.red(`[X] Error importing ${dumpFile}. See errors in ${errorFile}`));
|
|
22
20
|
}
|
|
23
21
|
else {
|
|
@@ -31,6 +29,7 @@ async function restoreCollectionData(sdk, log, batchSize, dumpFile, index, colle
|
|
|
31
29
|
action: "mWrite",
|
|
32
30
|
index: "",
|
|
33
31
|
collection: "",
|
|
32
|
+
strict: true,
|
|
34
33
|
body: {
|
|
35
34
|
documents: [{}],
|
|
36
35
|
},
|
|
@@ -90,8 +89,8 @@ async function restoreCollectionData(sdk, log, batchSize, dumpFile, index, colle
|
|
|
90
89
|
mWriteRequest.body.documents = documents;
|
|
91
90
|
sdk
|
|
92
91
|
.query(mWriteRequest)
|
|
93
|
-
.then(() => {
|
|
94
|
-
total +=
|
|
92
|
+
.then((response) => {
|
|
93
|
+
total += response.result.successes.length;
|
|
95
94
|
process.stdout.write(` ${total} documents imported`);
|
|
96
95
|
process.stdout.write("\r");
|
|
97
96
|
resolve(undefined);
|