UNPKG

5.61 kBJavaScriptView Raw
1"use strict";
2/*
3 * Copyright © 2018 Atomist, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18 return new (P || (P = Promise))(function (resolve, reject) {
19 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
22 step((generator = generator.apply(thisArg, _arguments || [])).next());
23 });
24};
25Object.defineProperty(exports, "__esModule", { value: true });
26const automation_client_1 = require("@atomist/automation-client");
27const sdm_1 = require("@atomist/sdm");
28const child_process_1 = require("child_process");
29const portfinder = require("portfinder");
30/**
31 * Deployer that uses `docker run` in order to deploy images produces by the `DockerBuild` goal.
32 */
33class DockerPerBranchDeployer {
34 constructor(options) {
35 this.options = options;
36 // Already allocated ports
37 this.repoBranchToPort = {};
38 // Keys are ports: values are containerIds
39 this.portToContainer = {};
40 }
41 deployProject(goalInvocation) {
42 return __awaiter(this, void 0, void 0, function* () {
43 const branch = goalInvocation.goalEvent.branch;
44 let port = this.repoBranchToPort[goalInvocation.id.repo + ":" + branch];
45 if (!port) {
46 port = yield portfinder.getPortPromise({ /*host: this.options.baseUrl,*/ port: this.options.lowerPort });
47 this.repoBranchToPort[goalInvocation.id.repo + ":" + branch] = port;
48 }
49 const existingContainer = this.portToContainer[port];
50 if (!!existingContainer) {
51 yield stopAndRemoveContainer(existingContainer);
52 }
53 else {
54 // Check we won't end with a crazy number of child processes
55 const presentCount = Object.keys(this.portToContainer)
56 .filter(n => typeof n === "number")
57 .length;
58 if (presentCount >= 5) {
59 throw new Error(`Unable to deploy project at ${goalInvocation.id} as limit of 5 has been reached`);
60 }
61 }
62 const name = `${goalInvocation.id.repo}_${branch}`;
63 const childProcess = child_process_1.spawn("docker", [
64 "run",
65 `-p${port}:${this.options.sourcePort}`,
66 `--name=${name}`,
67 goalInvocation.goalEvent.push.after.image.imageName,
68 ], {});
69 if (!childProcess.pid) {
70 throw new Error("Fatal error deploying using Docker");
71 }
72 const deployment = {
73 childProcess,
74 endpoint: `${this.options.baseUrl}:${port}`,
75 };
76 this.portToContainer[port] = name;
77 const newLineDelimitedLog = new sdm_1.DelimitedWriteProgressLogDecorator(goalInvocation.progressLog, "\n");
78 childProcess.stdout.on("data", what => newLineDelimitedLog.write(what.toString()));
79 childProcess.stderr.on("data", what => newLineDelimitedLog.write(what.toString()));
80 let stdout = "";
81 let stderr = "";
82 return new Promise((resolve, reject) => {
83 childProcess.stdout.addListener("data", what => {
84 if (!!what) {
85 stdout += what.toString();
86 }
87 if (this.options.successPatterns.some(successPattern => successPattern.test(stdout))) {
88 resolve(deployment);
89 }
90 });
91 childProcess.stderr.addListener("data", what => {
92 if (!!what) {
93 stderr += what.toString();
94 }
95 });
96 childProcess.addListener("exit", () => __awaiter(this, void 0, void 0, function* () {
97 if (this.options.successPatterns.some(successPattern => successPattern.test(stdout))) {
98 resolve(deployment);
99 }
100 else {
101 automation_client_1.logger.error("Docker deployment failure vvvvvvvvvvvvvvvvvvvvvv");
102 automation_client_1.logger.error("stdout:\n%s\nstderr:\n%s\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", stdout, stderr);
103 reject(new Error("Docker deployment failure"));
104 }
105 }));
106 childProcess.addListener("error", reject);
107 });
108 });
109 }
110}
111exports.DockerPerBranchDeployer = DockerPerBranchDeployer;
112function stopAndRemoveContainer(existingContainer) {
113 return sdm_1.execPromise("docker", [
114 "rm",
115 "-f",
116 existingContainer,
117 ]);
118}
119//# sourceMappingURL=DockerPerBranchDeployer.js.map
\No newline at end of file