@atomist/sdm-pack-docker
Version:
Extension Pack for an Atomist SDM to integrate Docker
121 lines • 5.7 kB
JavaScript
;
/*
* Copyright © 2019 Atomist, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const automation_client_1 = require("@atomist/automation-client");
const sdm_1 = require("@atomist/sdm");
const child_process_1 = require("child_process");
const portfinder = require("portfinder");
/**
* Deployer that uses `docker run` in order to deploy images produces by the `DockerBuild` goal.
*/
class DockerPerBranchDeployer {
constructor(options) {
this.options = options;
// Already allocated ports
this.repoBranchToPort = {};
// Keys are ports: values are containerIds
this.portToContainer = {};
}
// tslint:disable-next-line:deprecation
deployProject(goalInvocation) {
return __awaiter(this, void 0, void 0, function* () {
const branch = goalInvocation.goalEvent.branch;
let port = this.repoBranchToPort[goalInvocation.id.repo + ":" + branch];
if (!port) {
port = yield portfinder.getPortPromise({ /*host: this.options.baseUrl,*/ port: this.options.lowerPort });
this.repoBranchToPort[goalInvocation.id.repo + ":" + branch] = port;
}
const existingContainer = this.portToContainer[port];
if (!!existingContainer) {
yield stopAndRemoveContainer(existingContainer);
}
else {
// Check we won't end with a crazy number of child processes
const presentCount = Object.keys(this.portToContainer)
.filter(n => typeof n === "number")
.length;
if (presentCount >= 5) {
throw new Error(`Unable to deploy project at ${goalInvocation.id} as limit of 5 has been reached`);
}
}
const name = `${goalInvocation.id.repo}_${branch}`;
const childProcess = child_process_1.spawn("docker", [
"run",
`-p${port}:${this.options.sourcePort}`,
`--name=${name}`,
goalInvocation.goalEvent.push.after.image.imageName,
], {});
if (!childProcess.pid) {
throw new Error("Fatal error deploying using Docker");
}
const deployment = {
childProcess,
endpoint: `${this.options.baseUrl}:${port}`,
};
this.portToContainer[port] = name;
const newLineDelimitedLog = new sdm_1.DelimitedWriteProgressLogDecorator(goalInvocation.progressLog, "\n");
childProcess.stdout.on("data", what => newLineDelimitedLog.write(what.toString()));
childProcess.stderr.on("data", what => newLineDelimitedLog.write(what.toString()));
let stdout = "";
let stderr = "";
// tslint:disable-next-line:deprecation
return new Promise((resolve, reject) => {
childProcess.stdout.addListener("data", what => {
if (!!what) {
stdout += what.toString();
}
if (this.options.successPatterns.some(successPattern => successPattern.test(stdout))) {
resolve(deployment);
}
});
childProcess.stderr.addListener("data", what => {
if (!!what) {
stderr += what.toString();
}
});
childProcess.addListener("exit", () => __awaiter(this, void 0, void 0, function* () {
if (this.options.successPatterns.some(successPattern => successPattern.test(stdout))) {
resolve(deployment);
}
else {
automation_client_1.logger.error("Docker deployment failure vvvvvvvvvvvvvvvvvvvvvv");
automation_client_1.logger.error("stdout:\n%s\nstderr:\n%s\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", stdout, stderr);
reject(new Error("Docker deployment failure"));
}
}));
childProcess.addListener("error", reject);
});
});
}
}
exports.DockerPerBranchDeployer = DockerPerBranchDeployer;
function stopAndRemoveContainer(existingContainer) {
return sdm_1.execPromise("docker", [
"rm",
"-f",
existingContainer,
]);
}
//# sourceMappingURL=DockerPerBranchDeployer.js.map