kourou 0.27.1 → 0.28.0
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
CHANGED
|
@@ -27,7 +27,7 @@ $ npm install -g kourou
|
|
|
27
27
|
$ kourou COMMAND
|
|
28
28
|
running command...
|
|
29
29
|
$ kourou (-v|--version|version)
|
|
30
|
-
kourou/0.
|
|
30
|
+
kourou/0.28.0 darwin-arm64 node-v20.10.0
|
|
31
31
|
$ kourou --help [COMMAND]
|
|
32
32
|
USAGE
|
|
33
33
|
$ kourou COMMAND
|
|
@@ -161,6 +161,7 @@ All other arguments and options will be passed as-is to the `sdk:query` method.
|
|
|
161
161
|
* [`kourou instance:logs`](#kourou-instancelogs)
|
|
162
162
|
* [`kourou instance:spawn`](#kourou-instancespawn)
|
|
163
163
|
* [`kourou paas:deploy ENVIRONMENT APPLICATIONID IMAGE`](#kourou-paasdeploy-environment-applicationid-image)
|
|
164
|
+
* [`kourou paas:elasticsearch:dump ENVIRONMENT APPLICATIONID DUMPDIRECTORY`](#kourou-paaselasticsearchdump-environment-applicationid-dumpdirectory)
|
|
164
165
|
* [`kourou paas:init PROJECT`](#kourou-paasinit-project)
|
|
165
166
|
* [`kourou paas:login`](#kourou-paaslogin)
|
|
166
167
|
* [`kourou paas:logs ENVIRONMENT APPLICATION`](#kourou-paaslogs-environment-application)
|
|
@@ -1064,6 +1065,25 @@ OPTIONS
|
|
|
1064
1065
|
|
|
1065
1066
|
_See code: [lib/commands/paas/deploy.js](lib/commands/paas/deploy.js)_
|
|
1066
1067
|
|
|
1068
|
+
## `kourou paas:elasticsearch:dump ENVIRONMENT APPLICATIONID DUMPDIRECTORY`
|
|
1069
|
+
|
|
1070
|
+
Dump data from the Elasticsearch of a PaaS application
|
|
1071
|
+
|
|
1072
|
+
```
|
|
1073
|
+
USAGE
|
|
1074
|
+
$ kourou paas:elasticsearch:dump ENVIRONMENT APPLICATIONID DUMPDIRECTORY
|
|
1075
|
+
|
|
1076
|
+
ARGUMENTS
|
|
1077
|
+
ENVIRONMENT Project environment name
|
|
1078
|
+
APPLICATIONID Application Identifier
|
|
1079
|
+
DUMPDIRECTORY Directory where to store dump files
|
|
1080
|
+
|
|
1081
|
+
OPTIONS
|
|
1082
|
+
--batch-size=batch-size [default: 2000] Maximum batch size
|
|
1083
|
+
--help show CLI help
|
|
1084
|
+
--project=project Current PaaS project
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1067
1087
|
## `kourou paas:init PROJECT`
|
|
1068
1088
|
|
|
1069
1089
|
Initialize a PaaS project in current directory
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { flags } from "@oclif/command";
|
|
2
|
+
import { PaasKommand } from "../../../support/PaasKommand";
|
|
3
|
+
declare class PaasEsDump extends PaasKommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static flags: {
|
|
6
|
+
help: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
|
|
7
|
+
project: flags.IOptionFlag<string | undefined>;
|
|
8
|
+
"batch-size": import("@oclif/parser/lib/flags").IOptionFlag<number>;
|
|
9
|
+
};
|
|
10
|
+
static args: {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
required: boolean;
|
|
14
|
+
}[];
|
|
15
|
+
runSafe(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* @description Get all indexes from the Elasticsearch of the PaaS application.
|
|
18
|
+
* @returns The indexes.
|
|
19
|
+
*/
|
|
20
|
+
private getAllIndexes;
|
|
21
|
+
/**
|
|
22
|
+
* @description Dump documents from the Elasticsearch of the PaaS application.
|
|
23
|
+
* @param pitId ID of the PIT opened on Elasticsearch.
|
|
24
|
+
* @param searchAfter Cursor for dumping documents after a certain one.
|
|
25
|
+
* @returns The dumped documents.
|
|
26
|
+
*/
|
|
27
|
+
private dumpDocuments;
|
|
28
|
+
private dumpAllDocuments;
|
|
29
|
+
/**
|
|
30
|
+
* @description Finish the document dumping session.
|
|
31
|
+
* @param pitId ID of the PIT opened on Elasticsearch.
|
|
32
|
+
*/
|
|
33
|
+
private finishDump;
|
|
34
|
+
}
|
|
35
|
+
export default PaasEsDump;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const path_1 = (0, tslib_1.__importDefault)(require("path"));
|
|
5
|
+
const promises_1 = (0, tslib_1.__importDefault)(require("node:fs/promises"));
|
|
6
|
+
const ndjson_1 = (0, tslib_1.__importDefault)(require("ndjson"));
|
|
7
|
+
const command_1 = require("@oclif/command");
|
|
8
|
+
const PaasKommand_1 = require("../../../support/PaasKommand");
|
|
9
|
+
class PaasEsDump extends PaasKommand_1.PaasKommand {
|
|
10
|
+
async runSafe() {
|
|
11
|
+
// Check that the batch size is positive
|
|
12
|
+
if (this.flags["batch-size"] <= 0) {
|
|
13
|
+
this.logKo(`The batch size must be greater than zero. (Specified batch size: ${this.flags["batch-size"]})`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
// Log in to the PaaS
|
|
17
|
+
const apiKey = await this.getCredentials();
|
|
18
|
+
await this.initPaasClient({ apiKey });
|
|
19
|
+
const user = await this.paas.auth.getCurrentUser();
|
|
20
|
+
this.logInfo(`Logged as "${user._id}" for project "${this.flags.project || this.getProject()}"`);
|
|
21
|
+
// Create the dump directory
|
|
22
|
+
await promises_1.default.mkdir(this.args.dumpDirectory, { recursive: true });
|
|
23
|
+
// Dump the indexes
|
|
24
|
+
this.logInfo("Dumping Elasticsearch indexes...");
|
|
25
|
+
const indexesResult = await this.getAllIndexes();
|
|
26
|
+
await promises_1.default.writeFile(path_1.default.join(this.args.dumpDirectory, "indexes.json"), JSON.stringify(indexesResult));
|
|
27
|
+
this.logOk("Elasticsearch indexes dumped!");
|
|
28
|
+
// Dump all the documents
|
|
29
|
+
this.logInfo("Dumping Elasticsearch documents...");
|
|
30
|
+
await this.dumpAllDocuments();
|
|
31
|
+
this.logOk("Elasticsearch documents dumped!");
|
|
32
|
+
this.logOk(`The dumped files are available under "${path_1.default.resolve(this.args.dumpDirectory)}"`);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @description Get all indexes from the Elasticsearch of the PaaS application.
|
|
36
|
+
* @returns The indexes.
|
|
37
|
+
*/
|
|
38
|
+
async getAllIndexes() {
|
|
39
|
+
const { result } = await this.paas.query({
|
|
40
|
+
controller: "application/storage",
|
|
41
|
+
action: "getIndexes",
|
|
42
|
+
environmentId: this.args.environment,
|
|
43
|
+
projectId: this.flags.project || this.getProject(),
|
|
44
|
+
applicationId: this.args.applicationId,
|
|
45
|
+
body: {},
|
|
46
|
+
});
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* @description Dump documents from the Elasticsearch of the PaaS application.
|
|
51
|
+
* @param pitId ID of the PIT opened on Elasticsearch.
|
|
52
|
+
* @param searchAfter Cursor for dumping documents after a certain one.
|
|
53
|
+
* @returns The dumped documents.
|
|
54
|
+
*/
|
|
55
|
+
async dumpDocuments(pitId, searchAfter) {
|
|
56
|
+
const { result } = await this.paas.query({
|
|
57
|
+
controller: "application/storage",
|
|
58
|
+
action: "dumpDocuments",
|
|
59
|
+
environmentId: this.args.environment,
|
|
60
|
+
projectId: this.flags.project || this.getProject(),
|
|
61
|
+
applicationId: this.args.applicationId,
|
|
62
|
+
body: {
|
|
63
|
+
pitId,
|
|
64
|
+
searchAfter: JSON.stringify(searchAfter),
|
|
65
|
+
size: this.flags["batch-size"],
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
async dumpAllDocuments() {
|
|
71
|
+
// Prepare dumping all documents
|
|
72
|
+
let pitId = "";
|
|
73
|
+
let searchAfter = [];
|
|
74
|
+
let dumpedDocuments = 0;
|
|
75
|
+
let totalDocuments = 0;
|
|
76
|
+
const fd = await promises_1.default.open(path_1.default.join(this.args.dumpDirectory, "documents.jsonl"), "w");
|
|
77
|
+
const writeStream = fd.createWriteStream();
|
|
78
|
+
const ndjsonStream = ndjson_1.default.stringify();
|
|
79
|
+
writeStream.on("error", (error) => {
|
|
80
|
+
throw error;
|
|
81
|
+
});
|
|
82
|
+
ndjsonStream.on("data", (line) => {
|
|
83
|
+
writeStream.write(line);
|
|
84
|
+
});
|
|
85
|
+
const teardown = async () => {
|
|
86
|
+
// Finish the dump session if a PIT ID is set
|
|
87
|
+
if (pitId.length > 0) {
|
|
88
|
+
await this.finishDump(pitId);
|
|
89
|
+
}
|
|
90
|
+
// Close the open streams/file
|
|
91
|
+
writeStream.close();
|
|
92
|
+
await fd.close();
|
|
93
|
+
};
|
|
94
|
+
try {
|
|
95
|
+
// Dump the first batch
|
|
96
|
+
let result = await this.dumpDocuments(pitId, searchAfter);
|
|
97
|
+
let hits = result.hits.hits;
|
|
98
|
+
while (hits.length > 0) {
|
|
99
|
+
// Update the PIT ID and the cursor for the next dump
|
|
100
|
+
pitId = result.pit_id;
|
|
101
|
+
searchAfter = hits[hits.length - 1].sort;
|
|
102
|
+
// Save the documents
|
|
103
|
+
for (let i = 0; i < hits.length; ++i) {
|
|
104
|
+
ndjsonStream.write(hits[i]);
|
|
105
|
+
}
|
|
106
|
+
dumpedDocuments += hits.length;
|
|
107
|
+
totalDocuments = result.hits.total.value;
|
|
108
|
+
this.logInfo(`Dumping Elasticsearch documents: ${Math.floor(dumpedDocuments / totalDocuments * 100)}% (${dumpedDocuments}/${totalDocuments})`);
|
|
109
|
+
// Dump the next batch
|
|
110
|
+
result = await this.dumpDocuments(pitId, searchAfter);
|
|
111
|
+
hits = result.hits.hits;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
teardown();
|
|
116
|
+
this.logKo(`Error while dumping the documents: ${error}`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
// Finish the dump
|
|
120
|
+
teardown();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* @description Finish the document dumping session.
|
|
124
|
+
* @param pitId ID of the PIT opened on Elasticsearch.
|
|
125
|
+
*/
|
|
126
|
+
async finishDump(pitId) {
|
|
127
|
+
try {
|
|
128
|
+
await this.paas.query({
|
|
129
|
+
controller: "application/storage",
|
|
130
|
+
action: "finishDumpDocuments",
|
|
131
|
+
environmentId: this.args.environment,
|
|
132
|
+
projectId: this.flags.project || this.getProject(),
|
|
133
|
+
applicationId: this.args.applicationId,
|
|
134
|
+
body: {
|
|
135
|
+
pitId,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
this.logInfo(`Unable to cleanly finish the dump session: ${error}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
PaasEsDump.description = "Dump data from the Elasticsearch of a PaaS application";
|
|
145
|
+
PaasEsDump.flags = {
|
|
146
|
+
help: command_1.flags.help(),
|
|
147
|
+
project: command_1.flags.string({
|
|
148
|
+
description: "Current PaaS project",
|
|
149
|
+
}),
|
|
150
|
+
"batch-size": command_1.flags.integer({
|
|
151
|
+
description: "Maximum batch size",
|
|
152
|
+
default: 2000,
|
|
153
|
+
}),
|
|
154
|
+
};
|
|
155
|
+
PaasEsDump.args = [
|
|
156
|
+
{
|
|
157
|
+
name: "environment",
|
|
158
|
+
description: "Project environment name",
|
|
159
|
+
required: true,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "applicationId",
|
|
163
|
+
description: "Application Identifier",
|
|
164
|
+
required: true,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "dumpDirectory",
|
|
168
|
+
description: "Directory where to store dump files",
|
|
169
|
+
required: true,
|
|
170
|
+
}
|
|
171
|
+
];
|
|
172
|
+
exports.default = PaasEsDump;
|
|
@@ -14,10 +14,7 @@ class PaasSnapshotsRestore extends PaasKommand_1.PaasKommand {
|
|
|
14
14
|
environmentId: this.args.environment,
|
|
15
15
|
projectId: this.flags.project || this.getProject(),
|
|
16
16
|
applicationId: this.args.applicationId,
|
|
17
|
-
|
|
18
|
-
repository: "automated",
|
|
19
|
-
snapshot: this.args.snapshotId,
|
|
20
|
-
},
|
|
17
|
+
snapshotId: this.args.snapshotId
|
|
21
18
|
});
|
|
22
19
|
this.logInfo("Ok");
|
|
23
20
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kourou",
|
|
3
3
|
"description": "The CLI that helps you manage your Kuzzle instances",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.28.0",
|
|
5
5
|
"author": "The Kuzzle Team <support@kuzzle.io>",
|
|
6
6
|
"bin": {
|
|
7
7
|
"kourou": "./bin/run"
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@types/listr": "^0.14.2",
|
|
57
57
|
"@types/mocha": "^8.2.2",
|
|
58
58
|
"@types/ndjson": "^2.0.0",
|
|
59
|
-
"@types/node": "^
|
|
59
|
+
"@types/node": "^18.19.0",
|
|
60
60
|
"@types/node-emoji": "^1.8.1",
|
|
61
61
|
"@types/node-fetch": "^2.6.1",
|
|
62
62
|
"@types/tar": "^6.1.3",
|