@codiac.io/codiac-cli 1.3.140 → 1.3.142
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 +1 -1
- package/dist/apis/codiac-relay/gen/client.js +1 -1
- package/dist/apis/codiac-relay/gen/client.js.map +1 -1
- package/dist/apis/codiac-relay/gen/contracts/types.gen.d.ts +1 -1
- package/dist/apis/codiac-relay-nats/gen/client.js +2 -2
- package/dist/apis/codiac-relay-nats/gen/client.js.map +1 -1
- package/dist/apis/codiac-relay-nats/gen/contracts/types.gen.d.ts +1 -1
- package/dist/bootstrapper-for-api-clients.js +2 -0
- package/dist/bootstrapper-for-api-clients.js.map +1 -1
- package/dist/command-base-enterprise.d.ts +5 -0
- package/dist/command-base-enterprise.js +35 -24
- package/dist/command-base-enterprise.js.map +1 -1
- package/dist/commands/config/view.js +2 -2
- package/dist/commands/config/view.js.map +1 -1
- package/dist/relay/relay-container.d.ts +31 -47
- package/dist/relay/relay-container.js +311 -583
- package/dist/relay/relay-container.js.map +1 -1
- package/oclif.manifest.json +4 -3
- package/package.json +1 -1
|
@@ -1,660 +1,388 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.DEFAULT_IMAGE_TAG = exports.RelayContainer = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const rxjs_1 = require("rxjs");
|
|
6
6
|
const operators_1 = require("rxjs/operators");
|
|
7
7
|
const reqp = require("request-promise");
|
|
8
8
|
const os = require("os");
|
|
9
|
-
const fs = require("fs");
|
|
9
|
+
const fs = require("fs/promises");
|
|
10
10
|
const path = require("path");
|
|
11
11
|
const Nats = require("@nats-io/nats-core");
|
|
12
12
|
const Transport = require("@nats-io/transport-node");
|
|
13
|
-
const child_process_1 = require("child_process");
|
|
14
13
|
const inversify_1 = require("inversify");
|
|
15
|
-
const codiac_error_1 = require("@codiac.io/codiac-common/contracts/codiac-error");
|
|
16
|
-
const codiac_common_1 = require("@codiac.io/codiac-common");
|
|
17
|
-
const IBetterLogger_1 = require("@codiac.io/codiac-common/IBetterLogger");
|
|
18
|
-
const cli_tools_1 = require("@codiac.io/cli-tools");
|
|
19
|
-
const INTERFACES_CLI_1 = require("../ops/INTERFACES_CLI");
|
|
20
14
|
const Docker = require("dockerode");
|
|
15
|
+
const codiac_common_1 = require("@codiac.io/codiac-common");
|
|
16
|
+
const ops_1 = require("../ops");
|
|
21
17
|
const entities_1 = require("../ops/entities");
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
// Configuration defaults
|
|
19
|
+
const DEFAULT_CONFIG = {
|
|
20
|
+
IMAGE_NAME: "codiacimages/codiac-relay",
|
|
21
|
+
IMAGE_TAG: "1.6.61",
|
|
22
|
+
CONTAINER_NAME: "codiac-relay",
|
|
23
|
+
HEALTH_CHECK_URL: "http://localhost:5799/heartbeat-json",
|
|
24
|
+
RETRY_TIMEOUT_MINUTES: 1,
|
|
25
|
+
MAX_HEALTH_CHECK_RETRIES: 40,
|
|
26
|
+
HEALTH_CHECK_INTERVAL_MS: 3000,
|
|
27
|
+
EXPOSED_PORTS: {
|
|
28
|
+
"5799/tcp": {},
|
|
29
|
+
"5798/tcp": {},
|
|
30
|
+
"4222/tcp": {},
|
|
31
|
+
"9222/tcp": {},
|
|
32
|
+
},
|
|
33
|
+
PORT_BINDINGS: {
|
|
34
|
+
"5799/tcp": [{ HostPort: "5799" }],
|
|
35
|
+
"5798/tcp": [{ HostPort: "5798" }],
|
|
36
|
+
"4222/tcp": [{ HostPort: "4222" }],
|
|
37
|
+
"9222/tcp": [{ HostPort: "9222" }],
|
|
38
|
+
},
|
|
39
|
+
VOLUMES: { "/root/.codiac": {} },
|
|
40
|
+
BINDS: [`${os.homedir()}/.codiac:/root/.codiac`],
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Manages a single version of a Codiac Relay Docker container, ensuring only the specified version runs.
|
|
44
|
+
*/
|
|
27
45
|
let RelayContainer = class RelayContainer {
|
|
28
46
|
get userMessages() {
|
|
29
|
-
return this.
|
|
30
|
-
}
|
|
31
|
-
get dockerFailed$() {
|
|
32
|
-
return this.dockerFailedSubj.asObservable();
|
|
33
|
-
}
|
|
34
|
-
get docker$() {
|
|
35
|
-
return this.dockerSubj.asObservable();
|
|
36
|
-
}
|
|
37
|
-
get startFailed$() {
|
|
38
|
-
return this.startFailedSubj.asObservable();
|
|
47
|
+
return this.userMessagesSubj.asObservable();
|
|
39
48
|
}
|
|
40
49
|
get ready$() {
|
|
41
50
|
return this.readySubj.pipe((0, operators_1.distinctUntilChanged)());
|
|
42
51
|
}
|
|
43
|
-
constructor(styler, cliEnviro, logger, healthCheckUrl =
|
|
52
|
+
constructor(styler, cliEnviro, logger, healthCheckUrl = DEFAULT_CONFIG.HEALTH_CHECK_URL, retryTimeOut = DEFAULT_CONFIG.RETRY_TIMEOUT_MINUTES, projectRoot, localEntities = false) {
|
|
44
53
|
this.styler = styler;
|
|
45
54
|
this.cliEnviro = cliEnviro;
|
|
46
55
|
this.logger = logger;
|
|
47
|
-
this.healthCheckUrl = healthCheckUrl;
|
|
48
|
-
this.retryTimeOut = retryTimeOut;
|
|
49
56
|
this.projectRoot = projectRoot;
|
|
50
57
|
this.localEntities = localEntities;
|
|
51
|
-
this.
|
|
52
|
-
this.
|
|
53
|
-
this.
|
|
58
|
+
this.natsClient = new rxjs_1.BehaviorSubject(null);
|
|
59
|
+
this.destroySubj = new rxjs_1.Subject();
|
|
60
|
+
this.userMessagesSubj = new rxjs_1.BehaviorSubject(undefined);
|
|
61
|
+
this.readySubj = new rxjs_1.ReplaySubject(1);
|
|
62
|
+
this.readyFailedSubj = new rxjs_1.Subject();
|
|
63
|
+
this.connectionRefusedCount = new rxjs_1.BehaviorSubject(0);
|
|
54
64
|
this.silent = false;
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
this.MAXTRIESBEFORECONTAINERRESTART = 40; // Equivalent to over 40 seconds for the container to get healthy
|
|
59
|
-
this._natsClient = null;
|
|
60
|
-
this.isWin = process.platform === "win32";
|
|
61
|
-
// https://github.com/apocas/dockerode/issues/290
|
|
62
|
-
this.socketPath = this.isWin
|
|
63
|
-
? "//./pipe/docker_engine"
|
|
64
|
-
: undefined;
|
|
65
|
-
this._userMessages = new rxjs_1.BehaviorSubject(undefined);
|
|
66
|
-
// private startSubj: Subject<string> = new Subject<string>();
|
|
67
|
-
// private get start$(): Observable<string> {
|
|
68
|
-
// return this.startSubj.asObservable();
|
|
69
|
-
// }
|
|
70
|
-
this.dockerFailedSubj = new rxjs_1.Subject();
|
|
71
|
-
this.dockerSubj = new rxjs_1.Subject();
|
|
72
|
-
// started is based on the container we're trying to start
|
|
73
|
-
this.startFailedSubj = new rxjs_1.Subject();
|
|
74
|
-
this.readySubj = new rxjs_1.ReplaySubject();
|
|
75
|
-
this.promisifyStream = (stream) => new Promise((resolve, reject) => {
|
|
76
|
-
stream.on('data', (d) => this.logger.write(d.toString()));
|
|
77
|
-
stream.on('end', resolve);
|
|
78
|
-
stream.on('error', reject);
|
|
79
|
-
});
|
|
80
|
-
this._cliExec = new cli_tools_1.CliExec(logger);
|
|
81
|
-
this.docker = new Docker();
|
|
82
|
-
this.init();
|
|
65
|
+
this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), { HEALTH_CHECK_URL: healthCheckUrl, RETRY_TIMEOUT_MINUTES: retryTimeOut });
|
|
66
|
+
this.docker = this.instantiateDocker();
|
|
67
|
+
this.checkDockerAvailability();
|
|
83
68
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
* Does not throw: Logs any encountered errors and continues.
|
|
87
|
-
*/
|
|
88
|
-
createLocalDataFolders() {
|
|
89
|
-
var _a;
|
|
90
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
91
|
-
const folders = [
|
|
92
|
-
"cluster-images",
|
|
93
|
-
"templates",
|
|
94
|
-
"data/db",
|
|
95
|
-
"data/logs"
|
|
96
|
-
];
|
|
97
|
-
for (let folder of folders) {
|
|
98
|
-
try {
|
|
99
|
-
const fqn = path.posix.join(this.cliEnviro.localProgramFolder, folder);
|
|
100
|
-
if (!fs.existsSync(fqn)) {
|
|
101
|
-
yield fs.promises.mkdir(fqn, { recursive: true });
|
|
102
|
-
this.logger.debug("Created local data folder ".concat("[", fqn, "]."));
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
this.logger.error("Error creating local data folder ".concat("[", folder, "]: ", (_a = err.message) !== null && _a !== void 0 ? _a : "(no message available)"));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return;
|
|
110
|
-
});
|
|
69
|
+
instantiateDocker() {
|
|
70
|
+
return new Docker(process.platform === "win32" ? { socketPath: "//./pipe/docker_engine" } : {});
|
|
111
71
|
}
|
|
112
72
|
init() {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// This should hit anytime the image tag changes, which triggers the workflow to rip and replace if its not the same versions
|
|
116
|
-
(0, rxjs_1.of)(this.imageTag)
|
|
117
|
-
.pipe((0, operators_1.distinctUntilChanged)()) // i think to be able to change image dynamiclly
|
|
118
|
-
.pipe((0, operators_1.concatMap)(_ => this.versionMismatch())) //check the version mismatch or no version do some work
|
|
119
|
-
.pipe((0, operators_1.concatMap)(versionMismatch => {
|
|
120
|
-
if (versionMismatch) {
|
|
121
|
-
this._userMessages.next(`Version mismatch of the Relay container found. Updating to ${this.imageTag}`);
|
|
122
|
-
return this.stop()
|
|
123
|
-
.pipe((0, operators_1.concatMap)(_ => this.remove()))
|
|
124
|
-
.pipe((0, operators_1.concatMap)(_ => this.deleteRelayImage()))
|
|
125
|
-
.pipe((0, operators_1.concatMap)(_ => this.pullImage()));
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
// The api's may already be running. Let's see.
|
|
129
|
-
return (0, rxjs_1.of)("no work was done");
|
|
130
|
-
}
|
|
131
|
-
}))
|
|
132
|
-
.subscribe(_ => this.healthCheck());
|
|
133
|
-
// If we find docker is not started, we put ourselves into a loop, asking the user to kick it on
|
|
134
|
-
this.dockerFailed$
|
|
135
|
-
.pipe((0, operators_1.delay)(10000))
|
|
136
|
-
.pipe((0, operators_1.tap)(_ => {
|
|
137
|
-
this.logger.debug("Attempting to get service again");
|
|
138
|
-
this.getDocker();
|
|
139
|
-
}))
|
|
73
|
+
(0, rxjs_1.of)(`${this.config.IMAGE_NAME}:${this.config.IMAGE_TAG}`)
|
|
74
|
+
.pipe((0, operators_1.distinctUntilChanged)(), (0, operators_1.concatMap)(() => this.handleVersionMismatch()), (0, operators_1.takeUntil)(this.destroySubj))
|
|
140
75
|
.subscribe();
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
.pipe((0, operators_1.
|
|
144
|
-
this.execStart();
|
|
145
|
-
}))
|
|
146
|
-
.pipe((0, operators_1.takeUntil)(this.ready$))
|
|
147
|
-
.subscribe();
|
|
148
|
-
// If docker is running but the conainer failed to start. Kick on CONTAINER from image
|
|
149
|
-
(0, rxjs_1.combineLatest)([this.docker$, this.startFailed$])
|
|
150
|
-
.pipe((0, operators_1.tap)(([docker, containerName]) => {
|
|
151
|
-
this.createContainer();
|
|
152
|
-
}))
|
|
153
|
-
.pipe((0, operators_1.takeUntil)(this.ready$))
|
|
154
|
-
.subscribe();
|
|
155
|
-
// // Now our pipelines are defined and hot. We fire off the catalyst and notify user.
|
|
156
|
-
this.readyFailed$
|
|
157
|
-
.pipe((0, operators_1.take)(1))
|
|
158
|
-
.pipe((0, operators_1.tap)(() => {
|
|
159
|
-
this.logger.notice(this.styler.hilite(`Starting Services...`));
|
|
160
|
-
}))
|
|
161
|
-
.pipe((0, operators_1.tap)(() => {
|
|
162
|
-
// every three seconds we're going to health check until either ready or timeout
|
|
163
|
-
(0, rxjs_1.interval)(3000)
|
|
164
|
-
.pipe((0, operators_1.take)(100))
|
|
165
|
-
.pipe((0, operators_1.timeout)(this.retryTimeOut * 60000)) //minutes to miliseconds
|
|
166
|
-
.pipe((0, operators_1.takeUntil)(this.ready$))
|
|
167
|
-
.subscribe(() => this.healthCheck());
|
|
168
|
-
}))
|
|
76
|
+
this.readyFailedSubj
|
|
77
|
+
.pipe((0, operators_1.tap)(() => this.logNotice(this.styler.hilite("Starting Services..."))), (0, operators_1.concatMap)(() => (0, rxjs_1.interval)(this.config.HEALTH_CHECK_INTERVAL_MS)
|
|
78
|
+
.pipe((0, operators_1.timeout)(this.config.RETRY_TIMEOUT_MINUTES * 60000), (0, operators_1.take)(this.config.MAX_HEALTH_CHECK_RETRIES), (0, operators_1.takeUntil)(this.ready$), (0, operators_1.takeUntil)(this.destroySubj), (0, operators_1.concatMap)(() => this.performHealthCheck()))))
|
|
169
79
|
.subscribe();
|
|
170
80
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const output = new rxjs_1.Subject();
|
|
174
|
-
this._cliExec.execAsyncStdOut(command, { cwd: this.projectRoot }, IBetterLogger_1.LogLevel.debug, true)
|
|
175
|
-
.then((stdout) => {
|
|
176
|
-
this.logger.debug(`getRelayImageFromDockerPS - entered method`);
|
|
177
|
-
// Split the output into lines and parse each line as JSON
|
|
178
|
-
try {
|
|
179
|
-
if (stdout == undefined && stdout == "")
|
|
180
|
-
output.next(undefined);
|
|
181
|
-
else {
|
|
182
|
-
const listedContainers = stdout.split("\n");
|
|
183
|
-
let containerIds = [];
|
|
184
|
-
listedContainers.forEach(r => {
|
|
185
|
-
if (r.split(" ")[1].includes(this.imageName))
|
|
186
|
-
containerIds.push(r.split(" ")[0]);
|
|
187
|
-
});
|
|
188
|
-
output.next(containerIds);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
catch (parseError) {
|
|
192
|
-
this.logger.error(`getRelayImageFromDockerPS - Error parsing Docker output: ${parseError}`);
|
|
193
|
-
return parseError;
|
|
194
|
-
}
|
|
195
|
-
})
|
|
196
|
-
.catch(error => {
|
|
197
|
-
this.logger.debug(`getRelayImageFromDockerPS - Command failed: docker ps -a | grep -v ID`);
|
|
198
|
-
output.next(undefined);
|
|
199
|
-
});
|
|
200
|
-
return output.asObservable();
|
|
81
|
+
logDebug(message) {
|
|
82
|
+
this.logger.debug(message);
|
|
201
83
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
.catch(error => {
|
|
232
|
-
this.logger.debug(`getRelayImageFromDockerPS - Command failed: docker ps -a | grep -v ID`);
|
|
233
|
-
output.next(undefined);
|
|
234
|
-
});
|
|
235
|
-
return output.asObservable();
|
|
84
|
+
logNotice(message) {
|
|
85
|
+
this.logger.notice(message);
|
|
86
|
+
}
|
|
87
|
+
createLocalDataFolders() {
|
|
88
|
+
if (!this.localEntities)
|
|
89
|
+
return (0, rxjs_1.of)(true);
|
|
90
|
+
const folders = ["cluster-images", "templates", "data/db", "data/logs"];
|
|
91
|
+
return (0, rxjs_1.from)(Promise.all(folders.map((folder) => fs.mkdir(path.posix.join(this.cliEnviro.localProgramFolder, folder), { recursive: true })
|
|
92
|
+
.then(() => this.logDebug(`Created local data folder [${folder}]`))
|
|
93
|
+
.catch((err) => {
|
|
94
|
+
this.logger.error(`Error creating local data folder [${folder}]: ${err.message}`);
|
|
95
|
+
throw err;
|
|
96
|
+
})))).pipe((0, operators_1.map)(() => true), (0, operators_1.catchError)(() => (0, rxjs_1.of)(false)));
|
|
97
|
+
}
|
|
98
|
+
checkDockerAvailability() {
|
|
99
|
+
(0, rxjs_1.from)(this.docker.info())
|
|
100
|
+
.pipe((0, operators_1.tap)(() => {
|
|
101
|
+
this.logDebug("Docker daemon is available");
|
|
102
|
+
this.init();
|
|
103
|
+
}), (0, operators_1.catchError)((err) => {
|
|
104
|
+
const msg = "Can you start Docker for me?";
|
|
105
|
+
this.logger.error(msg, err);
|
|
106
|
+
this.userMessagesSubj.next(msg);
|
|
107
|
+
return (0, rxjs_1.of)(null).pipe((0, operators_1.delay)(6000), (0, operators_1.tap)(() => {
|
|
108
|
+
this.docker = this.instantiateDocker();
|
|
109
|
+
this.checkDockerAvailability();
|
|
110
|
+
}));
|
|
111
|
+
}), (0, operators_1.takeUntil)(this.destroySubj))
|
|
112
|
+
.subscribe();
|
|
236
113
|
}
|
|
237
114
|
getRunningContainers() {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
this._cliExec.execAsyncStdOut(command, { cwd: this.projectRoot }, IBetterLogger_1.LogLevel.debug, true)
|
|
244
|
-
.then((stdout) => {
|
|
245
|
-
// Split the output into lines and parse each line as JSON
|
|
246
|
-
try {
|
|
247
|
-
if (stdout != undefined && stdout != "") {
|
|
248
|
-
const images = JSON.parse(stdout);
|
|
249
|
-
output.next(images);
|
|
250
|
-
}
|
|
251
|
-
else
|
|
252
|
-
output.next(undefined);
|
|
253
|
-
}
|
|
254
|
-
catch (parseError) {
|
|
255
|
-
this.logger.error(`Error getting running containers: ${parseError}`);
|
|
256
|
-
output.next(undefined);
|
|
257
|
-
}
|
|
258
|
-
})
|
|
259
|
-
.catch(error => {
|
|
260
|
-
this.logger.debug(`getRunningContainers - ${error.message}`);
|
|
261
|
-
output.next(undefined);
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
this.logger.debug(`getRunningContainers - No running containers found.`);
|
|
266
|
-
return (0, rxjs_1.of)(undefined);
|
|
267
|
-
}
|
|
268
|
-
return output.asObservable();
|
|
115
|
+
return (0, rxjs_1.from)(this.docker.listContainers({ all: true })).pipe((0, operators_1.map)((containers) => containers.filter((c) => c.Image.includes(this.config.IMAGE_NAME) && c.State === "running")), (0, operators_1.concatMap)((matching) => matching.length === 0
|
|
116
|
+
? (0, rxjs_1.of)([])
|
|
117
|
+
: (0, rxjs_1.from)(Promise.all(matching.map((c) => this.docker.getContainer(c.Id).inspect())))), (0, operators_1.catchError)((err) => {
|
|
118
|
+
this.logger.error(`Failed to list containers: ${err.message}`);
|
|
119
|
+
return (0, rxjs_1.of)([]);
|
|
269
120
|
}));
|
|
270
121
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
return this.getRunningContainers().pipe((0, operators_1.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
return !(currentVersion.RepoTags[0].includes(exports.DEFAULT_IMAGE_TAG));
|
|
122
|
+
handleVersionMismatch() {
|
|
123
|
+
const imageRef = `${this.config.IMAGE_NAME}:${this.config.IMAGE_TAG}`;
|
|
124
|
+
return this.getRunningContainers().pipe((0, operators_1.concatMap)((containers) => {
|
|
125
|
+
if (containers.length === 0) {
|
|
126
|
+
this.logDebug("No running containers found");
|
|
127
|
+
return this.startContainer();
|
|
278
128
|
}
|
|
279
|
-
|
|
280
|
-
|
|
129
|
+
const mismatchChecks = containers.map((c) => {
|
|
130
|
+
const imageName = c.Image;
|
|
131
|
+
if (imageName.startsWith("sha256:")) {
|
|
132
|
+
return (0, rxjs_1.from)(this.docker.getImage(imageName).inspect()).pipe((0, operators_1.map)((info) => !(info.RepoTags || []).includes(imageRef)), (0, operators_1.catchError)((err) => {
|
|
133
|
+
this.logger.error(`Failed to inspect image ${imageName}: ${err.message}`);
|
|
134
|
+
return (0, rxjs_1.of)(true);
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
return (0, rxjs_1.of)(!imageName.includes(this.config.IMAGE_TAG));
|
|
138
|
+
});
|
|
139
|
+
return (0, rxjs_1.forkJoin)(mismatchChecks).pipe((0, operators_1.map)((results) => results.some((hasMismatch) => hasMismatch)), (0, operators_1.concatMap)((hasMismatch) => {
|
|
140
|
+
if (!hasMismatch) {
|
|
141
|
+
this.logDebug(`Container version matches ${imageRef}`);
|
|
142
|
+
return this.performHealthCheck();
|
|
143
|
+
}
|
|
144
|
+
this.userMessagesSubj.next(`Version mismatch detected. Updating to ${imageRef}`);
|
|
145
|
+
return this.stopAndRemoveContainers().pipe((0, operators_1.concatMap)(() => this.deleteMismatchedImages()), (0, operators_1.concatMap)(() => this.pullImage()), (0, operators_1.concatMap)(() => this.startContainer()));
|
|
146
|
+
}));
|
|
281
147
|
}));
|
|
282
148
|
}
|
|
283
|
-
|
|
284
|
-
return this.
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const localRelayImages = response;
|
|
289
|
-
localRelayImages
|
|
290
|
-
.filter(i => i.Tag != this.imageTag)
|
|
291
|
-
.forEach(image => {
|
|
292
|
-
this._cliExec.execAsyncStdOut(`docker rmi ${image.Repository}:${image.Tag}`, { cwd: this.projectRoot }, IBetterLogger_1.LogLevel.debug, true)
|
|
293
|
-
.then((fullfulled) => {
|
|
294
|
-
this.logger.debug('pull response', fullfulled);
|
|
295
|
-
this.createContainer();
|
|
296
|
-
output.next('Remove Image complete');
|
|
297
|
-
this._userMessages.next(`Removing extra image(s) complete`);
|
|
298
|
-
})
|
|
299
|
-
.catch(error => {
|
|
300
|
-
this.logger.debug(`Removing Relay image failed.`);
|
|
301
|
-
});
|
|
302
|
-
});
|
|
149
|
+
stopAndRemoveContainers() {
|
|
150
|
+
return this.getRunningContainers().pipe((0, operators_1.concatMap)((containers) => {
|
|
151
|
+
if (containers.length === 0) {
|
|
152
|
+
this.logDebug("No containers to stop or remove");
|
|
153
|
+
return (0, rxjs_1.of)(false);
|
|
303
154
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
155
|
+
return (0, rxjs_1.from)(Promise.all(containers.map((c) => this.docker.getContainer(c.Id).stop().catch((err) => {
|
|
156
|
+
if (err.statusCode !== 404)
|
|
157
|
+
throw err;
|
|
158
|
+
})))).pipe((0, operators_1.concatMap)(() => (0, rxjs_1.from)(Promise.all(containers.map((c) => this.docker.getContainer(c.Id).remove({ force: true }).catch((err) => {
|
|
159
|
+
if (err.statusCode !== 404)
|
|
160
|
+
throw err;
|
|
161
|
+
}))))), (0, operators_1.tap)(() => this.logDebug("All containers stopped and removed")), (0, operators_1.map)(() => true), (0, operators_1.catchError)((err) => {
|
|
162
|
+
this.logger.error(`Failed to stop/remove containers: ${err.message}`);
|
|
163
|
+
return (0, rxjs_1.of)(false);
|
|
164
|
+
}));
|
|
308
165
|
}));
|
|
309
166
|
}
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const images = lines.map(line => JSON.parse(line));
|
|
320
|
-
output.next(images);
|
|
321
|
-
}
|
|
322
|
-
else
|
|
323
|
-
output.next(undefined);
|
|
324
|
-
}
|
|
325
|
-
catch (parseError) {
|
|
326
|
-
this.logger.error(`Error getting relay image: ${parseError}`);
|
|
327
|
-
return parseError;
|
|
167
|
+
deleteMismatchedImages() {
|
|
168
|
+
const imageRef = `${this.config.IMAGE_NAME}:${this.config.IMAGE_TAG}`;
|
|
169
|
+
return (0, rxjs_1.from)(this.docker.listImages()).pipe((0, operators_1.map)((images) => images
|
|
170
|
+
.filter((img) => img.RepoTags &&
|
|
171
|
+
img.RepoTags.some((tag) => tag.includes(this.config.IMAGE_NAME) && tag !== imageRef))
|
|
172
|
+
.map((img) => img.RepoTags[0])), (0, operators_1.concatMap)((imagesToRemove) => {
|
|
173
|
+
if (imagesToRemove.length === 0) {
|
|
174
|
+
this.logDebug("No mismatched images to delete");
|
|
175
|
+
return (0, rxjs_1.of)(false);
|
|
328
176
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
177
|
+
return (0, rxjs_1.from)(Promise.all(imagesToRemove.map((tag) => this.docker.getImage(tag).remove()))).pipe((0, operators_1.tap)(() => {
|
|
178
|
+
this.userMessagesSubj.next("Removing extra images complete");
|
|
179
|
+
imagesToRemove.forEach((tag) => this.logDebug(`Removed image ${tag}`));
|
|
180
|
+
}), (0, operators_1.map)(() => true), (0, operators_1.catchError)((err) => {
|
|
181
|
+
this.logger.error(`Failed to delete images: ${err.message}`);
|
|
182
|
+
return (0, rxjs_1.of)(false);
|
|
183
|
+
}));
|
|
184
|
+
}));
|
|
334
185
|
}
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
.
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return parseError;
|
|
186
|
+
pullImage() {
|
|
187
|
+
const imageRef = `${this.config.IMAGE_NAME}:${this.config.IMAGE_TAG}`;
|
|
188
|
+
return (0, rxjs_1.from)(this.docker.getImage(imageRef).inspect()).pipe((0, operators_1.tap)(() => {
|
|
189
|
+
this.logDebug(`Image ${imageRef} already exists`);
|
|
190
|
+
this.userMessagesSubj.next(`Image ${imageRef} already exists`);
|
|
191
|
+
}), (0, operators_1.map)(() => true), (0, operators_1.catchError)((err) => {
|
|
192
|
+
if (err.statusCode !== 404) {
|
|
193
|
+
this.logger.error(`Error inspecting image ${imageRef}: ${err.message}`);
|
|
194
|
+
this.userMessagesSubj.next(`Error inspecting image: ${err.message}`);
|
|
195
|
+
return (0, rxjs_1.of)(false);
|
|
346
196
|
}
|
|
347
|
-
|
|
348
|
-
.
|
|
349
|
-
this.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
197
|
+
this.logNotice(`Fetching image ${imageRef}. This may take a few minutes...`);
|
|
198
|
+
this.userMessagesSubj.next(`Fetching image ${imageRef}...`);
|
|
199
|
+
return (0, rxjs_1.from)(this.docker.pull(imageRef, {})).pipe((0, operators_1.concatMap)((stream) => new rxjs_1.Observable((observer) => {
|
|
200
|
+
this.docker.modem.followProgress(stream, (err) => {
|
|
201
|
+
if (err) {
|
|
202
|
+
this.logger.error(`Failed to pull image ${imageRef}: ${err.message}`);
|
|
203
|
+
this.userMessagesSubj.next(`Fetching failed: ${err.message}`);
|
|
204
|
+
observer.error(err);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
this.logDebug(`Image ${imageRef} pulled successfully`);
|
|
208
|
+
this.userMessagesSubj.next("Relay fetch complete");
|
|
209
|
+
observer.next(true);
|
|
210
|
+
observer.complete();
|
|
211
|
+
}, (progress) => { var _a; return this.userMessagesSubj.next(`Pulling ${(_a = progress.id) !== null && _a !== void 0 ? _a : imageRef} : Layer ${progress.status}`); });
|
|
212
|
+
})), (0, operators_1.catchError)((err) => {
|
|
213
|
+
this.logger.error(`Failed to pull image ${imageRef}: ${err.message}`);
|
|
214
|
+
this.userMessagesSubj.next(`Fetching failed: ${err.message}`);
|
|
215
|
+
return (0, rxjs_1.of)(false);
|
|
216
|
+
}));
|
|
217
|
+
}));
|
|
353
218
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
this.
|
|
358
|
-
|
|
359
|
-
this.performHttpHealthCheck();
|
|
360
|
-
}
|
|
361
|
-
else if (this.healthCheckUrl.startsWith('nats')) {
|
|
362
|
-
this.performNatsHealthCheck();
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
this.logger.debug(`healthCheck - Unknown healthCheckUrl scheme: ${this.healthCheckUrl}`);
|
|
366
|
-
this.readyFailed$.next();
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
catch (error) {
|
|
370
|
-
this.logger.debug(`healthCheck failed (${(_a = error.name) !== null && _a !== void 0 ? _a : ""} ${(_b = error.message) !== null && _b !== void 0 ? _b : ""})`, JSON.stringify(error, null, 2));
|
|
371
|
-
this.readyFailed$.next();
|
|
372
|
-
}
|
|
219
|
+
performHealthCheck() {
|
|
220
|
+
this.logDebug(`Checking ${this.config.CONTAINER_NAME} health...`);
|
|
221
|
+
return this.config.HEALTH_CHECK_URL.startsWith("http")
|
|
222
|
+
? this.performHttpHealthCheck()
|
|
223
|
+
: this.performNatsHealthCheck();
|
|
373
224
|
}
|
|
374
225
|
performHttpHealthCheck() {
|
|
375
|
-
reqp.get(this.
|
|
376
|
-
.
|
|
377
|
-
this.logger.trace(`healthCheck - ...${this.containerName} ready.`);
|
|
226
|
+
return (0, rxjs_1.from)(reqp.get(this.config.HEALTH_CHECK_URL)).pipe((0, operators_1.map)(() => {
|
|
227
|
+
this.logger.trace(`${this.config.CONTAINER_NAME} is healthy`);
|
|
378
228
|
this.readySubj.next(true);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
this.
|
|
229
|
+
this.connectionRefusedCount.next(0);
|
|
230
|
+
return true;
|
|
231
|
+
}), (0, operators_1.catchError)((err) => {
|
|
232
|
+
var _a;
|
|
233
|
+
if (((_a = err.error) === null || _a === void 0 ? void 0 : _a.code) === "ECONNREFUSED") {
|
|
234
|
+
this.connectionRefusedCount.next(this.connectionRefusedCount.value + 1);
|
|
235
|
+
if (this.connectionRefusedCount.value >= this.config.MAX_HEALTH_CHECK_RETRIES) {
|
|
236
|
+
this.logDebug("Max retries reached, restarting container");
|
|
237
|
+
this.startContainer().pipe((0, operators_1.take)(1)).subscribe();
|
|
238
|
+
this.connectionRefusedCount.next(0);
|
|
387
239
|
}
|
|
388
240
|
}
|
|
389
|
-
this.
|
|
390
|
-
this.
|
|
391
|
-
|
|
241
|
+
this.logDebug(`Health check failed: ${err.message}`);
|
|
242
|
+
this.readyFailedSubj.next();
|
|
243
|
+
return (0, rxjs_1.of)(false);
|
|
244
|
+
}));
|
|
392
245
|
}
|
|
393
246
|
performNatsHealthCheck() {
|
|
394
|
-
(() => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
try {
|
|
398
|
-
// Only create the client if it doesn't exist or is closed
|
|
399
|
-
if (!this._natsClient || this._natsClient.isClosed()) {
|
|
400
|
-
const opts = {
|
|
401
|
-
servers: this.healthCheckUrl,
|
|
402
|
-
};
|
|
403
|
-
nc = (yield Transport.connect(opts));
|
|
404
|
-
this._natsClient = nc;
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
nc = this._natsClient;
|
|
408
|
-
}
|
|
409
|
-
// Heartbeat subject
|
|
410
|
-
const subject = "dmz.get.heartbeat-json";
|
|
411
|
-
const timeoutMs = 2000;
|
|
412
|
-
// Use NATS request/reply, Promise style
|
|
413
|
-
yield nc.request(subject, Nats.Empty, { timeout: timeoutMs });
|
|
414
|
-
this.logger.trace(`healthCheck - ...${this.containerName} NATS heartbeat received.`);
|
|
415
|
-
this.readySubj.next(true);
|
|
416
|
-
// On success, close client and clear reference
|
|
417
|
-
yield nc.close();
|
|
418
|
-
this._natsClient = null;
|
|
419
|
-
this.connectionRefusedCount = 0;
|
|
247
|
+
return (0, rxjs_1.from)((() => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
248
|
+
if (!this.natsClient.value || this.natsClient.value.isClosed()) {
|
|
249
|
+
this.natsClient.next(yield Transport.connect({ servers: this.config.HEALTH_CHECK_URL }));
|
|
420
250
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
this._natsClient = null;
|
|
251
|
+
return this.natsClient.value.request("dmz.get.heartbeat-json", Nats.Empty, { timeout: 2000 });
|
|
252
|
+
}))()).pipe((0, operators_1.map)(() => {
|
|
253
|
+
this.logger.trace(`${this.config.CONTAINER_NAME} NATS heartbeat received`);
|
|
254
|
+
this.readySubj.next(true);
|
|
255
|
+
this.connectionRefusedCount.next(0);
|
|
256
|
+
return true;
|
|
257
|
+
}), (0, operators_1.catchError)((err) => {
|
|
258
|
+
this.connectionRefusedCount.next(this.connectionRefusedCount.value + 1);
|
|
259
|
+
if (this.connectionRefusedCount.value >= this.config.MAX_HEALTH_CHECK_RETRIES) {
|
|
260
|
+
this.logDebug("Max retries reached, restarting container");
|
|
261
|
+
this.startContainer().pipe((0, operators_1.take)(1)).subscribe();
|
|
262
|
+
this.connectionRefusedCount.next(0);
|
|
435
263
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
// stdio: "inherit",
|
|
446
|
-
// stdio: [process.stdin, process.stdout, process.stderr, process.st], // TODO: Capture stderr instead
|
|
447
|
-
shell: true
|
|
448
|
-
};
|
|
449
|
-
const ls = (0, child_process_1.spawn)(cmdStop, options);
|
|
450
|
-
// ls.stdout?.on('data', (data: any) => {
|
|
451
|
-
// result$.next(true);
|
|
452
|
-
// });
|
|
453
|
-
// ls.stdout?.on('error', (data: any) => {
|
|
454
|
-
// result$.next(false);
|
|
455
|
-
// });
|
|
456
|
-
// ls.on('error', (data: any) => {
|
|
457
|
-
// result$.next(false);
|
|
458
|
-
// });
|
|
459
|
-
ls.on('close', (data) => {
|
|
460
|
-
result$.next(false);
|
|
461
|
-
});
|
|
462
|
-
return result$.asObservable();
|
|
463
|
-
}
|
|
464
|
-
remove() {
|
|
465
|
-
// fire off this command in a separate cli window
|
|
466
|
-
this.getAllContainersOfRelayImage().pipe((0, operators_1.map)(response => {
|
|
467
|
-
if (response && response.length > 0) {
|
|
468
|
-
response.forEach(containerId => {
|
|
469
|
-
let cmdStop = `docker rm ${containerId} -f`;
|
|
470
|
-
let options = {
|
|
471
|
-
cwd: this.projectRoot,
|
|
472
|
-
shell: true
|
|
473
|
-
};
|
|
474
|
-
const ls = (0, child_process_1.spawn)(cmdStop, options);
|
|
475
|
-
ls.on('close', (data) => {
|
|
476
|
-
result$.next(false);
|
|
477
|
-
});
|
|
478
|
-
});
|
|
264
|
+
this.logDebug(`NATS health check failed: ${err.message}`);
|
|
265
|
+
this.readyFailedSubj.next();
|
|
266
|
+
return (0, rxjs_1.of)(false);
|
|
267
|
+
}), (0, operators_1.tap)({
|
|
268
|
+
complete: () => {
|
|
269
|
+
if (this.natsClient.value && !this.natsClient.value.isClosed()) {
|
|
270
|
+
this.natsClient.value.close().catch((err) => this.logger.error(`Failed to close NATS client: ${err.message}`));
|
|
271
|
+
this.natsClient.next(null);
|
|
272
|
+
}
|
|
479
273
|
}
|
|
480
|
-
}))
|
|
481
|
-
.subscribe();
|
|
482
|
-
let result$ = new rxjs_1.Subject();
|
|
483
|
-
result$.subscribe();
|
|
484
|
-
return result$.asObservable();
|
|
274
|
+
}));
|
|
485
275
|
}
|
|
486
|
-
|
|
487
|
-
|
|
276
|
+
startContainer() {
|
|
277
|
+
return this.createLocalDataFolders().pipe((0, operators_1.concatMap)(() => this.pullImage()), (0, operators_1.concatMap)(() => this.createContainer()), (0, operators_1.concatMap)(() => this.startContainerInternal()), (0, operators_1.catchError)((err) => {
|
|
278
|
+
this.logger.error(`Failed to start container: ${err.message}`);
|
|
279
|
+
this.userMessagesSubj.next(`Failed to start container: ${err.message}`);
|
|
280
|
+
return (0, rxjs_1.of)(false);
|
|
281
|
+
}));
|
|
488
282
|
}
|
|
489
283
|
createContainer() {
|
|
490
|
-
var _a
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
ExposedPorts: {
|
|
497
|
-
"5799/tcp": {},
|
|
498
|
-
"5798/tcp": {},
|
|
499
|
-
"4222/tcp": {},
|
|
500
|
-
"9222/tcp": {}
|
|
501
|
-
},
|
|
284
|
+
var _a;
|
|
285
|
+
const containerConfig = {
|
|
286
|
+
Image: `${this.config.IMAGE_NAME}:${this.config.IMAGE_TAG}`,
|
|
287
|
+
name: this.config.CONTAINER_NAME,
|
|
288
|
+
Hostname: this.config.CONTAINER_NAME,
|
|
289
|
+
ExposedPorts: Object.assign({}, DEFAULT_CONFIG.EXPOSED_PORTS),
|
|
502
290
|
HostConfig: {
|
|
503
|
-
Binds: [
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
// `${os.homedir}/.azure:/root/.azure`
|
|
507
|
-
],
|
|
508
|
-
PortBindings: {
|
|
509
|
-
"5799/tcp": [
|
|
510
|
-
{
|
|
511
|
-
HostPort: "5799"
|
|
512
|
-
}
|
|
513
|
-
],
|
|
514
|
-
"5798/tcp": [
|
|
515
|
-
{
|
|
516
|
-
HostPort: "5798"
|
|
517
|
-
}
|
|
518
|
-
],
|
|
519
|
-
"4222/tcp": [
|
|
520
|
-
{
|
|
521
|
-
HostPort: "4222"
|
|
522
|
-
}
|
|
523
|
-
],
|
|
524
|
-
"9222/tcp": [
|
|
525
|
-
{
|
|
526
|
-
HostPort: "9222"
|
|
527
|
-
}
|
|
528
|
-
]
|
|
529
|
-
},
|
|
530
|
-
RestartPolicy: {
|
|
531
|
-
Name: "unless-stopped"
|
|
532
|
-
}
|
|
533
|
-
},
|
|
534
|
-
Volumes: {
|
|
535
|
-
"/root/.codiac": {}
|
|
536
|
-
// "/root/.kube": {},
|
|
537
|
-
// "/root/.azure": {}
|
|
291
|
+
Binds: [...DEFAULT_CONFIG.BINDS],
|
|
292
|
+
PortBindings: Object.assign({}, DEFAULT_CONFIG.PORT_BINDINGS),
|
|
293
|
+
RestartPolicy: { Name: "unless-stopped" },
|
|
538
294
|
},
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
]
|
|
295
|
+
Volumes: Object.assign({}, DEFAULT_CONFIG.VOLUMES),
|
|
296
|
+
Env: [`HOST_PLATFORM=${process.platform}`],
|
|
542
297
|
};
|
|
543
|
-
if (this.localEntities
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
(_a =
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
container.Entrypoint = ["./start-relay-w-nats-and-local-entities.sh"];
|
|
298
|
+
if (this.localEntities) {
|
|
299
|
+
containerConfig.ExposedPorts["27017/tcp"] = {};
|
|
300
|
+
containerConfig.HostConfig.PortBindings["27017/tcp"] = [{ HostPort: "27017" }];
|
|
301
|
+
(_a = containerConfig.HostConfig.Binds) === null || _a === void 0 ? void 0 : _a.push(`${os.homedir()}/.codiac/data/db:/data/db`, `${os.homedir()}/.codiac/data/logs:/data/logs`);
|
|
302
|
+
containerConfig.Volumes["/data/db"] = {};
|
|
303
|
+
containerConfig.Volumes["/data/logs"] = {};
|
|
304
|
+
containerConfig.Entrypoint = ["./start-relay-w-nats-and-local-entities.sh"];
|
|
551
305
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
this.logger.trace(`createContainer - Created ${this.containerName}`);
|
|
557
|
-
this.execStart();
|
|
558
|
-
})
|
|
559
|
-
.catch(error => {
|
|
560
|
-
if (error.statusCode == 409)
|
|
561
|
-
this.execStart(); //Already in use
|
|
562
|
-
else {
|
|
563
|
-
this.logger.debug(`createContainer - Failed to create ${this.containerName}`, JSON.stringify(error, null, 2));
|
|
564
|
-
this.pullImage();
|
|
306
|
+
return (0, rxjs_1.from)(this.docker.createContainer(containerConfig)).pipe((0, operators_1.tap)(() => this.logDebug(`Created container ${this.config.CONTAINER_NAME}`)), (0, operators_1.map)(() => true), (0, operators_1.catchError)((err) => {
|
|
307
|
+
if (err.statusCode === 409) {
|
|
308
|
+
this.logDebug(`Container ${this.config.CONTAINER_NAME} already exists`);
|
|
309
|
+
return (0, rxjs_1.of)(true);
|
|
565
310
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return output.asObservable();
|
|
311
|
+
this.logger.error(`Failed to create container: ${err.message}`);
|
|
312
|
+
return this.pullImage();
|
|
313
|
+
}));
|
|
570
314
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
this.
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
315
|
+
startContainerInternal() {
|
|
316
|
+
return (0, rxjs_1.from)(this.docker.getContainer(this.config.CONTAINER_NAME).inspect()).pipe((0, operators_1.concatMap)((info) => {
|
|
317
|
+
if (info.State.Running) {
|
|
318
|
+
this.logDebug(`Container ${this.config.CONTAINER_NAME} is already running`);
|
|
319
|
+
return this.performHealthCheck();
|
|
320
|
+
}
|
|
321
|
+
return (0, rxjs_1.from)(this.docker.getContainer(this.config.CONTAINER_NAME).start()).pipe((0, operators_1.tap)(() => {
|
|
322
|
+
this.logDebug(`Started container ${this.config.CONTAINER_NAME}`);
|
|
323
|
+
this.userMessagesSubj.next("Starting Relay...");
|
|
324
|
+
this.performHealthCheck().subscribe();
|
|
325
|
+
}), (0, operators_1.map)(() => true));
|
|
326
|
+
}), (0, operators_1.catchError)((err) => {
|
|
327
|
+
if (err.statusCode === 404) {
|
|
328
|
+
this.logDebug(`Container ${this.config.CONTAINER_NAME} not found, creating...`);
|
|
329
|
+
return this.createContainer();
|
|
330
|
+
}
|
|
331
|
+
this.logger.error(`Failed to start container: ${err.message}`);
|
|
332
|
+
return (0, rxjs_1.of)(false);
|
|
333
|
+
}));
|
|
589
334
|
}
|
|
590
|
-
|
|
591
|
-
(0, rxjs_1.
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
this.
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
// Hard stop on 20 tries, reboot it
|
|
606
|
-
if (this.serverErrorCount == 20) {
|
|
607
|
-
this.stop()
|
|
608
|
-
.pipe((0, operators_1.map)(x => this.startFailedSubj.next(this.containerName)))
|
|
609
|
-
.pipe((0, operators_1.take)(1))
|
|
610
|
-
.subscribe();
|
|
611
|
-
this.serverErrorCount = 0;
|
|
612
|
-
}
|
|
613
|
-
});
|
|
614
|
-
}))
|
|
615
|
-
.subscribe();
|
|
335
|
+
stop() {
|
|
336
|
+
return (0, rxjs_1.from)(this.docker.getContainer(this.config.CONTAINER_NAME).inspect()).pipe((0, operators_1.concatMap)((info) => {
|
|
337
|
+
if (!info.State.Running) {
|
|
338
|
+
this.logDebug(`Container ${this.config.CONTAINER_NAME} is not running`);
|
|
339
|
+
return (0, rxjs_1.of)(false);
|
|
340
|
+
}
|
|
341
|
+
return (0, rxjs_1.from)(this.docker.getContainer(this.config.CONTAINER_NAME).stop()).pipe((0, operators_1.tap)(() => this.logDebug(`Stopped container ${this.config.CONTAINER_NAME}`)), (0, operators_1.map)(() => true));
|
|
342
|
+
}), (0, operators_1.catchError)((err) => {
|
|
343
|
+
if (err.statusCode === 404) {
|
|
344
|
+
this.logDebug(`Container ${this.config.CONTAINER_NAME} does not exist`);
|
|
345
|
+
return (0, rxjs_1.of)(false);
|
|
346
|
+
}
|
|
347
|
+
this.logger.error(`Failed to stop container: ${err.message}`);
|
|
348
|
+
return (0, rxjs_1.of)(false);
|
|
349
|
+
}));
|
|
616
350
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
.
|
|
625
|
-
|
|
626
|
-
});
|
|
351
|
+
remove() {
|
|
352
|
+
return this.stop().pipe((0, operators_1.concatMap)(() => (0, rxjs_1.from)(this.docker.getContainer(this.config.CONTAINER_NAME).remove({ force: true })).pipe((0, operators_1.tap)(() => this.logDebug(`Removed container ${this.config.CONTAINER_NAME}`)), (0, operators_1.map)(() => true), (0, operators_1.catchError)((err) => {
|
|
353
|
+
if (err.statusCode === 404) {
|
|
354
|
+
this.logDebug(`Container ${this.config.CONTAINER_NAME} does not exist`);
|
|
355
|
+
return (0, rxjs_1.of)(false);
|
|
356
|
+
}
|
|
357
|
+
this.logger.error(`Failed to remove container: ${err.message}`);
|
|
358
|
+
return (0, rxjs_1.of)(false);
|
|
359
|
+
}))));
|
|
627
360
|
}
|
|
628
|
-
|
|
629
|
-
this.
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
this.
|
|
637
|
-
this.
|
|
638
|
-
this.
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
this._userMessages.next(msg);
|
|
646
|
-
this.dockerFailedSubj.next();
|
|
647
|
-
return (0, rxjs_1.of)(this.docker);
|
|
648
|
-
}))
|
|
649
|
-
.pipe((0, operators_1.take)(1))
|
|
650
|
-
.subscribe();
|
|
361
|
+
destroy() {
|
|
362
|
+
return this.stop().pipe((0, operators_1.concatMap)(() => this.remove()), (0, operators_1.tap)(() => {
|
|
363
|
+
if (this.natsClient.value && !this.natsClient.value.isClosed()) {
|
|
364
|
+
this.natsClient.value.close().catch((err) => this.logger.error(`Failed to close NATS client: ${err.message}`));
|
|
365
|
+
this.natsClient.next(null);
|
|
366
|
+
}
|
|
367
|
+
this.destroySubj.next();
|
|
368
|
+
this.destroySubj.complete();
|
|
369
|
+
this.readySubj.complete();
|
|
370
|
+
this.readyFailedSubj.complete();
|
|
371
|
+
this.userMessagesSubj.complete();
|
|
372
|
+
this.connectionRefusedCount.complete();
|
|
373
|
+
this.logDebug("RelayContainer destroyed");
|
|
374
|
+
}), (0, operators_1.map)(() => true), (0, operators_1.catchError)((err) => {
|
|
375
|
+
this.logger.error(`Failed to destroy RelayContainer: ${err.message}`);
|
|
376
|
+
return (0, rxjs_1.of)(false);
|
|
377
|
+
}));
|
|
651
378
|
}
|
|
652
379
|
};
|
|
653
380
|
RelayContainer = tslib_1.__decorate([
|
|
654
|
-
tslib_1.__param(0, (0, inversify_1.inject)(
|
|
381
|
+
tslib_1.__param(0, (0, inversify_1.inject)(ops_1.INTERFACES_CLI.IOutputStyler)),
|
|
655
382
|
tslib_1.__param(1, (0, inversify_1.inject)(entities_1.CliEnviro)),
|
|
656
383
|
tslib_1.__param(2, (0, inversify_1.inject)(codiac_common_1.INTERFACES.IBetterLogger)),
|
|
657
384
|
tslib_1.__metadata("design:paramtypes", [Object, entities_1.CliEnviro, Object, String, Number, String, Boolean])
|
|
658
385
|
], RelayContainer);
|
|
659
386
|
exports.RelayContainer = RelayContainer;
|
|
387
|
+
exports.DEFAULT_IMAGE_TAG = DEFAULT_CONFIG.IMAGE_TAG;
|
|
660
388
|
//# sourceMappingURL=relay-container.js.map
|