ServiceManager Migrated

This commit is contained in:
Kasra Bigdeli
2018-11-19 21:26:05 -08:00
parent ca69be70d1
commit bfc890107f
10 changed files with 352 additions and 322 deletions
+5 -7
View File
@@ -1,5 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jwt = require("jsonwebtoken");
const uuid = require("uuid/v4");
const bcrypt = require("bcryptjs");
@@ -148,10 +147,7 @@ class Authenticator {
});
});
}
}
const authenticatorCache = {};
exports = {
get: function (namespace) {
static get(namespace) {
if (!namespace) {
return undefined;
}
@@ -162,6 +158,8 @@ exports = {
}
}
return authenticatorCache[namespace];
},
};
}
}
const authenticatorCache = {};
module.exports = Authenticator;
//# sourceMappingURL=Authenticator.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+134 -130
View File
@@ -1,32 +1,34 @@
const CaptainConstants = require('../utils/CaptainConstants');
const Logger = require('../utils/Logger');
const fs = require('fs-extra');
const tar = require('tar');
const path = require('path');
const CaptainManager = require('./CaptainManager');
const ApiStatusCodes = require('../api/ApiStatusCodes');
const TemplateHelper = require('./TemplateHelper');
const Authenticator = require('./Authenticator');
const GitHelper = require('../utils/GitHelper');
const uuid = require('uuid/v4');
const requireFromString = require('require-from-string');
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CaptainConstants = require("../utils/CaptainConstants");
const Logger = require("../utils/Logger");
const fs = require("fs-extra");
const tar = require("tar");
const path = require("path");
const CaptainManager = require("./CaptainManager");
const ApiStatusCodes = require("../api/ApiStatusCodes");
const TemplateHelper = require("./TemplateHelper");
const Authenticator = require("./Authenticator");
const GitHelper = require("../utils/GitHelper");
const uuid = require("uuid/v4");
const requireFromString = require("require-from-string");
const BUILD_LOG_SIZE = 50;
const SOURCE_FOLDER_NAME = 'src';
const DOCKER_FILE = 'Dockerfile';
const CAPTAIN_DEFINITION_FILE = 'captain-definition';
const PLACEHOLDER_DOCKER_FILE_CONTENT = 'FROM ' + CaptainConstants.appPlaceholderImageName +
const SOURCE_FOLDER_NAME = "src";
const DOCKER_FILE = "Dockerfile";
const CAPTAIN_DEFINITION_FILE = "captain-definition";
const PLACEHOLDER_DOCKER_FILE_CONTENT = "FROM " + CaptainConstants.appPlaceholderImageName +
'\nCMD [ "npm", "start" ]';
function getRawImageSourceFolder(imageName, newVersionPulled) {
return CaptainConstants.captainRawImagesDir + '/' + imageName + '/' + newVersionPulled + '/' + SOURCE_FOLDER_NAME;
return CaptainConstants.captainRawImagesDir + "/" + imageName + "/" + newVersionPulled + "/" + SOURCE_FOLDER_NAME;
}
function getRawImageBaseFolder(imageName, newVersionPulled) {
return CaptainConstants.captainRawImagesDir + '/' + imageName + '/' + newVersionPulled;
return CaptainConstants.captainRawImagesDir + "/" + imageName + "/" + newVersionPulled;
}
function getTarImageBaseFolder(imageName, newVersionPulled) {
return CaptainConstants.captainTarImagesDir + '/' + imageName + '/' + newVersionPulled;
return CaptainConstants.captainTarImagesDir + "/" + imageName + "/" + newVersionPulled;
}
function getCaptainDefinitionTempFolder(serviceName, randomSuffix) {
return CaptainConstants.captainDefinitionTempDir + '/' + serviceName + '/' + randomSuffix;
return CaptainConstants.captainDefinitionTempDir + "/" + serviceName + "/" + randomSuffix;
}
class BuildLog {
constructor(size) {
@@ -34,8 +36,8 @@ class BuildLog {
this.clear();
}
onBuildFailed(error) {
this.log('----------------------');
this.log('Deploy failed!');
this.log("----------------------");
this.log("Deploy failed!");
this.log(error);
this.isBuildFailed = true;
}
@@ -44,11 +46,11 @@ class BuildLog {
this.firstLineNumber = -this.size;
this.lines = [];
for (let i = 0; i < this.size; i++) {
this.lines.push('');
this.lines.push("");
}
}
log(msg) {
msg = (msg || '') + '';
msg = (msg || "") + "";
this.lines.shift();
this.lines.push(msg);
this.firstLineNumber++;
@@ -65,6 +67,9 @@ class BuildLog {
}
class ServiceManager {
constructor(user, dockerApi, loadBalancerManager) {
this.user = user;
this.dockerApi = dockerApi;
this.loadBalancerManager = loadBalancerManager;
this.user = user;
this.dataStore = user.dataStore;
this.dockerApi = dockerApi;
@@ -77,12 +82,12 @@ class ServiceManager {
return this.isReady;
}
createTarFarFromCaptainContent(captainDefinitionContent, appName, tarDestination) {
let serviceName = this.dataStore.getServiceName(appName);
let captainDefinitionDirPath;
const serviceName = this.dataStore.getServiceName(appName);
let captainDefinitionDirPath = undefined;
return Promise.resolve()
.then(function () {
for (let i = 0; i < 100; i++) {
let temp = getCaptainDefinitionTempFolder(serviceName, uuid());
const temp = getCaptainDefinitionTempFolder(serviceName, uuid());
if (!fs.pathExistsSync(temp)) {
captainDefinitionDirPath = temp;
break;
@@ -91,7 +96,7 @@ class ServiceManager {
if (!captainDefinitionDirPath) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Cannot create a temp file! Something is seriously wrong with the temp folder");
}
return fs.outputFile(captainDefinitionDirPath + '/' + CAPTAIN_DEFINITION_FILE, captainDefinitionContent);
return fs.outputFile(captainDefinitionDirPath + "/" + CAPTAIN_DEFINITION_FILE, captainDefinitionContent);
})
.then(function () {
return tar.c({
@@ -100,6 +105,9 @@ class ServiceManager {
}, [CAPTAIN_DEFINITION_FILE]);
})
.then(function () {
if (!captainDefinitionDirPath) {
throw new Error("captainDefinitionDirPath is NULL");
}
return fs.remove(captainDefinitionDirPath);
});
}
@@ -114,22 +122,22 @@ class ServiceManager {
* @returns {Promise<void>}
*/
createImage(appName, source, gitHash) {
Logger.d('Creating image for: ' + appName);
Logger.d("Creating image for: " + appName);
const self = this;
let imageName = this.dataStore.getImageName(CaptainManager.get().getDockerAuthObject(), appName);
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
let newVersion = null;
let rawImageSourceFolder = null;
let rawImageBaseFolder = null;
let tarImageBaseFolder = null;
let tarballFilePath = null;
let dockerFilePath = null;
const imageName = this.dataStore.getImageName(CaptainManager.get().getDockerAuthObject(), appName);
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
let newVersion;
let rawImageSourceFolder;
let rawImageBaseFolder;
let tarImageBaseFolder;
let tarballFilePath;
let dockerFilePath;
this.activeBuilds[appName] = true;
this.buildLogs[appName] = this.buildLogs[appName] || new BuildLog(BUILD_LOG_SIZE);
this.buildLogs[appName].clear();
this.buildLogs[appName].log('------------------------- ' + (new Date()));
this.buildLogs[appName].log('Build started for ' + appName);
this.buildLogs[appName].log("------------------------- " + (new Date()));
this.buildLogs[appName].log("Build started for " + appName);
return Promise.resolve()
.then(function () {
return dataStore.getAppsDataStore().getNewVersion(appName);
@@ -138,16 +146,16 @@ class ServiceManager {
newVersion = newVersionPulled;
rawImageSourceFolder = getRawImageSourceFolder(imageName, newVersionPulled);
rawImageBaseFolder = getRawImageBaseFolder(imageName, newVersionPulled);
dockerFilePath = rawImageBaseFolder + '/' + DOCKER_FILE;
dockerFilePath = rawImageBaseFolder + "/" + DOCKER_FILE;
tarImageBaseFolder = getTarImageBaseFolder(imageName, newVersionPulled);
tarballFilePath = tarImageBaseFolder + '/image.tar';
tarballFilePath = tarImageBaseFolder + "/image.tar";
return fs.ensureDir(rawImageSourceFolder)
.then(function () {
return rawImageSourceFolder;
});
})
.then(function (rawImageSourceFolder) {
let promiseToFetchDirectory = null;
let promiseToFetchDirectory;
if (source.pathToSrcTarballFile) {
promiseToFetchDirectory = tar
.x({
@@ -159,7 +167,7 @@ class ServiceManager {
});
}
else if (source.repoInfo) {
let repoInfo = source.repoInfo;
const repoInfo = source.repoInfo;
promiseToFetchDirectory = GitHelper
.clone(repoInfo.user, repoInfo.password, repoInfo.repo, repoInfo.branch, rawImageSourceFolder)
.then(function () {
@@ -174,18 +182,18 @@ class ServiceManager {
return dataStore.getAppsDataStore().setGitHash(appName, newVersion, gitHashToSave);
})
.then(function () {
return fs.pathExists(rawImageSourceFolder + '/' + CAPTAIN_DEFINITION_FILE);
return fs.pathExists(rawImageSourceFolder + "/" + CAPTAIN_DEFINITION_FILE);
})
.then(function (exists) {
if (!exists) {
Logger.d('Captain Definition does not exist in the base tar. Looking inside...');
Logger.d("Captain Definition does not exist in the base tar. Looking inside...");
// check if there is only one child
// check if it's a directory
// check if captain definition exists in it
// rename rawImageSourceFolder to rawImageSourceFolder+'.bak'
// move the child directory out to base and rename it to rawImageSourceFolder
// read captain definition from the folder and return it.
let directoryInside = null;
let directoryInside;
return new Promise(function (resolve, reject) {
fs.readdir(rawImageSourceFolder, function (err, files) {
if (err) {
@@ -207,14 +215,14 @@ class ServiceManager {
if (!captainDefinitionExists) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Captain Definition file does not exist!");
}
const BAK = '.bak';
const BAK = ".bak";
fs.renameSync(rawImageSourceFolder, rawImageSourceFolder + BAK);
fs.renameSync(path.join(rawImageSourceFolder + BAK, directoryInside), rawImageSourceFolder);
});
}
})
.then(function () {
return fs.readJson(rawImageSourceFolder + '/' + CAPTAIN_DEFINITION_FILE);
return fs.readJson(rawImageSourceFolder + "/" + CAPTAIN_DEFINITION_FILE);
})
.then(function (data) {
if (!data) {
@@ -224,11 +232,11 @@ class ServiceManager {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Captain Definition version is empty!");
}
if (data.schemaVersion === 1) {
let templateIdTag = data.templateId;
let dockerfileLines = data.dockerfileLines;
let hasDockerfileLines = dockerfileLines && dockerfileLines.length > 0;
const templateIdTag = data.templateId;
const dockerfileLines = data.dockerfileLines;
const hasDockerfileLines = dockerfileLines && dockerfileLines.length > 0;
if (hasDockerfileLines && !templateIdTag) {
return dockerfileLines.join('\n');
return dockerfileLines.join("\n");
}
else if (!hasDockerfileLines && templateIdTag) {
return TemplateHelper.get().getDockerfileContentFromTemplateTag(templateIdTag);
@@ -258,30 +266,30 @@ class ServiceManager {
return dockerApi
.buildImageFromDockerFile(imageName, newVersion, tarballFilePath, self.buildLogs[appName])
.catch(function (error) {
throw ApiStatusCodes.createError(ApiStatusCodes.BUILD_ERROR, ('' + error).trim());
throw ApiStatusCodes.createError(ApiStatusCodes.BUILD_ERROR, ("" + error).trim());
});
})
.then(function () {
Logger.d('Cleaning up up the files... ' + tarImageBaseFolder + ' and ' + rawImageBaseFolder);
Logger.d("Cleaning up up the files... " + tarImageBaseFolder + " and " + rawImageBaseFolder);
return fs.remove(tarImageBaseFolder);
})
.then(function () {
return fs.remove(rawImageBaseFolder);
})
.then(function () {
let authObj = CaptainManager.get().getDockerAuthObject();
const authObj = CaptainManager.get().getDockerAuthObject();
if (!authObj) {
Logger.d('No Docker Auth is found. Skipping pushing the image.');
Logger.d("No Docker Auth is found. Skipping pushing the image.");
return true;
}
Logger.d('Docker Auth is found. Pushing the image...');
Logger.d("Docker Auth is found. Pushing the image...");
return dockerApi
.pushImage(imageName, newVersion, authObj, self.buildLogs[appName])
.catch(function (error) {
return new Promise(function (resolve, reject) {
Logger.e('PUSH FAILED');
Logger.e("PUSH FAILED");
Logger.e(error);
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'Push failed: ' + error));
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Push failed: " + error));
});
});
})
@@ -300,14 +308,14 @@ class ServiceManager {
const self = this;
return Promise.resolve()
.then(function () {
Logger.d('Verifying Captain owns domain: ' + customDomain);
return CaptainManager.get().verifyCaptainOwnsDomainOrThrow(customDomain);
Logger.d("Verifying Captain owns domain: " + customDomain);
return CaptainManager.get().verifyCaptainOwnsDomainOrThrow(customDomain, undefined);
})
.then(function () {
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
Logger.d('Enabling SSL for: ' + appName + ' on ' + customDomain);
Logger.d("Enabling SSL for: " + appName + " on " + customDomain);
return self.dataStore.getAppsDataStore().verifyCustomDomainBelongsToApp(appName, customDomain);
})
.then(function () {
@@ -324,20 +332,20 @@ class ServiceManager {
const self = this;
return Promise.resolve()
.then(function () {
let rootDomain = self.dataStore.getRootDomain();
let dotRootDomain = "." + rootDomain;
const rootDomain = self.dataStore.getRootDomain();
const dotRootDomain = "." + rootDomain;
if (!customDomain || !(/^[a-z0-9\-\.]+$/.test(customDomain))) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME, 'Domain name is not accepted. Please use alphanumerical domains such as myapp.google123.ca');
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME, "Domain name is not accepted. Please use alphanumerical domains such as myapp.google123.ca");
}
if (customDomain.length > 80) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME, 'Domain name is not accepted. Please use alphanumerical domains less than 80 characters in length.');
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME, "Domain name is not accepted. Please use alphanumerical domains less than 80 characters in length.");
}
if (customDomain.indexOf('..') >= 0) {
if (customDomain.indexOf("..") >= 0) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME, 'Domain name is not accepted. You cannot have two consecutive periods ".." inside a domain name. Please use alphanumerical domains such as myapp.google123.ca');
}
if (customDomain.indexOf(dotRootDomain) >= 0 &&
(customDomain.indexOf(dotRootDomain) + dotRootDomain.length) === customDomain.length) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME, 'Domain name is not accepted. Custom domain cannot be subdomain of root domain.');
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME, "Domain name is not accepted. Custom domain cannot be subdomain of root domain.");
}
})
.then(function () {
@@ -345,9 +353,9 @@ class ServiceManager {
})
.then(function () {
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
Logger.d('Enabling custom domain for: ' + appName);
Logger.d("Enabling custom domain for: " + appName);
return self.dataStore.getAppsDataStore().addCustomDomainForApp(appName, customDomain);
})
.then(function () {
@@ -359,9 +367,9 @@ class ServiceManager {
return Promise.resolve()
.then(function () {
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
Logger.d('Removing custom domain for: ' + appName);
Logger.d("Removing custom domain for: " + appName);
return self.dataStore.getAppsDataStore().removeCustomDomainForApp(appName, customDomain);
})
.then(function () {
@@ -370,23 +378,22 @@ class ServiceManager {
}
enableSslForApp(appName) {
const self = this;
let rootDomain = null;
let app = null;
let rootDomain;
return Promise.resolve()
.then(function () {
return self.verifyCaptainOwnsGenericSubDomain(appName);
})
.then(function () {
Logger.d('Enabling SSL for: ' + appName);
Logger.d("Enabling SSL for: " + appName);
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
return self.dataStore.getRootDomain();
})
.then(function (val) {
rootDomain = val;
if (!rootDomain) {
throw new Error('No rootDomain! Cannot verify domain');
throw new Error("No rootDomain! Cannot verify domain");
}
})
.then(function () {
@@ -394,7 +401,7 @@ class ServiceManager {
return self.dataStore.getAppsDataStore().getAppDefinition(appName);
})
.then(function () {
return appName + '.' + rootDomain;
return appName + "." + rootDomain;
})
.then(function (domainName) {
return CaptainManager.get().requestCertificateForDomain(domainName);
@@ -408,11 +415,11 @@ class ServiceManager {
}
verifyCaptainOwnsGenericSubDomain(appName) {
const self = this;
let rootDomain = null;
let rootDomain;
return Promise.resolve()
.then(function () {
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
return self.dataStore.getRootDomain();
})
@@ -424,22 +431,22 @@ class ServiceManager {
return self.dataStore.getAppsDataStore().getAppDefinition(appName);
})
.then(function () {
return appName + '.' + rootDomain;
return appName + "." + rootDomain;
})
.then(function (domainName) {
Logger.d('Verifying Captain owns domain: ' + domainName);
return CaptainManager.get().verifyCaptainOwnsDomainOrThrow(domainName);
Logger.d("Verifying Captain owns domain: " + domainName);
return CaptainManager.get().verifyCaptainOwnsDomainOrThrow(domainName, undefined);
});
}
removeApp(appName) {
Logger.d('Removing service for: ' + appName);
Logger.d("Removing service for: " + appName);
const self = this;
let serviceName = this.dataStore.getServiceName(appName);
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
const serviceName = this.dataStore.getServiceName(appName);
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
return Promise.resolve()
.then(function () {
Logger.d('Check if service is running: ' + serviceName);
Logger.d("Check if service is running: " + serviceName);
return dockerApi
.isServiceRunningByName(serviceName);
})
@@ -449,7 +456,7 @@ class ServiceManager {
.removeService(serviceName);
}
else {
Logger.w('Cannot delete service... It is not running: ' + serviceName);
Logger.w("Cannot delete service... It is not running: " + serviceName);
return true;
}
})
@@ -461,11 +468,11 @@ class ServiceManager {
});
}
getUnusedImages(mostRecentLimit) {
Logger.d('Getting unused images, excluding most recent ones: ' + mostRecentLimit);
Logger.d("Getting unused images, excluding most recent ones: " + mostRecentLimit);
const self = this;
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
let allImages = null;
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
let allImages;
return Promise.resolve()
.then(function () {
return dockerApi
@@ -476,7 +483,7 @@ class ServiceManager {
return dataStore.getAppsDataStore().getAppDefinitions();
})
.then(function (apps) {
let unusedImages = [];
const unusedImages = [];
for (let i = 0; i < allImages.length; i++) {
const img = allImages[i];
let imageInUse = false;
@@ -484,7 +491,7 @@ class ServiceManager {
for (let j = 0; j < img.RepoTags.length; j++) {
const repoTag = img.RepoTags[j];
Object.keys(apps).forEach(function (key, index) {
let app = apps[key];
const app = apps[key];
app.appName = key;
for (let k = 0; k < (mostRecentLimit + 1); k++) {
if (repoTag.indexOf(dataStore.getImageNameWithoutAuthObj(app.appName, Number(app.deployedVersion) - k)) >= 0) {
@@ -497,7 +504,7 @@ class ServiceManager {
if (!imageInUse) {
unusedImages.push({
id: img.Id,
description: (img.RepoTags && img.RepoTags.length) ? img.RepoTags[0] : 'untagged'
description: (img.RepoTags && img.RepoTags.length) ? img.RepoTags[0] : "untagged"
});
}
}
@@ -505,11 +512,9 @@ class ServiceManager {
});
}
deleteImages(imageIds) {
Logger.d('Deleting images...');
Logger.d("Deleting images...");
const self = this;
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
let allImages = null;
const dockerApi = this.dockerApi;
return Promise.resolve()
.then(function () {
return dockerApi
@@ -517,44 +522,43 @@ class ServiceManager {
});
}
ensureServiceInitedAndUpdated(appName, version) {
Logger.d('Ensure service inited and Updated for: ' + appName);
Logger.d("Ensure service inited and Updated for: " + appName);
const self = this;
let serviceName = this.dataStore.getServiceName(appName);
const serviceName = this.dataStore.getServiceName(appName);
const dockerAuthObject = CaptainManager.get().getDockerAuthObject();
let imageName = this.dataStore.getImageName(dockerAuthObject, appName, version);
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
let app = null;
const imageName = this.dataStore.getImageName(dockerAuthObject, appName, version);
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
let app;
return dataStore.getAppsDataStore().setDeployedVersion(appName, version)
.then(function () {
return dataStore.getAppsDataStore().getAppDefinition(appName);
})
.then(function (appFound) {
app = appFound;
Logger.d('Check if service is running: ' + serviceName);
Logger.d("Check if service is running: " + serviceName);
return dockerApi
.isServiceRunningByName(serviceName);
})
.then(function (isRunning) {
if (isRunning) {
Logger.d('Service is already running: ' + serviceName);
Logger.d("Service is already running: " + serviceName);
return true;
}
else {
Logger.d('Creating service: ' + serviceName + ' with image: ' + imageName);
Logger.d("Creating service: " + serviceName + " with image: " + imageName);
// if we pass in networks here. Almost always it results in a delayed update which causes
// update errors if they happen right away!
return dockerApi
.createServiceOnNodeId(imageName, serviceName);
.createServiceOnNodeId(imageName, serviceName, undefined, undefined, undefined, undefined, undefined);
}
})
.then(function () {
return self.createPreDeployFunctionIfExist(app);
})
.then(function (preDeployFunction) {
Logger.d('Updating service: ' + serviceName + ' with image: ' + imageName);
return dockerApi
.updateService(serviceName, imageName, app.volumes, app.networks, app.envVars, null, dockerAuthObject, Number(app.instanceCount), app.nodeId, dataStore.getNameSpace(), app, preDeployFunction);
Logger.d("Updating service: " + serviceName + " with image: " + imageName);
return dockerApi.updateService(serviceName, imageName, app.volumes, app.networks, app.envVars, undefined, dockerAuthObject, Number(app.instanceCount), app.nodeId, dataStore.getNameSpace(), undefined, app, preDeployFunction);
})
.then(function () {
return new Promise(function (resolve) {
@@ -569,7 +573,7 @@ class ServiceManager {
createPreDeployFunctionIfExist(app) {
let preDeployFunction = app.preDeployFunction;
if (!preDeployFunction) {
return null;
return undefined;
}
/*
////////////////////////////////// Expected content of the file //////////////////////////
@@ -585,15 +589,15 @@ class ServiceManager {
});
};
*/
preDeployFunction = preDeployFunction + '\n\n module.exports = preDeployFunction';
preDeployFunction = preDeployFunction + "\n\n module.exports = preDeployFunction";
return requireFromString(preDeployFunction);
}
updateAppDefinition(appName, instanceCount, envVars, volumes, nodeId, notExposeAsWebApp, forceSsl, ports, appPushWebhook, customNginxConfig, preDeployFunction) {
const self = this;
const dataStore = this.dataStore;
const dockerApi = this.dockerApi;
let serviceName = null;
let checkIfNodeIdExists = function (nodeIdToCheck) {
let serviceName;
const checkIfNodeIdExists = function (nodeIdToCheck) {
return dockerApi
.getNodesInfo()
.then(function (nodeInfo) {
@@ -666,13 +670,13 @@ class ServiceManager {
* @returns the active build that it finds
*/
isAnyBuildRunning() {
let activeBuilds = this.activeBuilds;
for (let appName in activeBuilds) {
const activeBuilds = this.activeBuilds;
for (const appName in activeBuilds) {
if (!!activeBuilds[appName]) {
return appName;
}
}
return null;
return undefined;
}
getBuildStatus(appName) {
const self = this;
@@ -684,17 +688,17 @@ class ServiceManager {
};
}
logBuildFailed(appName, error) {
error = (error || '') + '';
error = (error || "") + "";
this.buildLogs[appName] = this.buildLogs[appName] || new BuildLog(BUILD_LOG_SIZE);
this.buildLogs[appName].onBuildFailed(error);
}
updateServiceOnDefinitionUpdate(appName) {
const self = this;
let serviceName = this.dataStore.getServiceName(appName);
const serviceName = this.dataStore.getServiceName(appName);
const dockerAuthObject = CaptainManager.get().getDockerAuthObject();
const dataStore = this.dataStore;
const dockerApi = this.dockerApi;
let appFound = null;
let appFound;
return Promise.resolve()
.then(function () {
return dataStore.getAppsDataStore().getAppDefinition(appName);
@@ -702,24 +706,24 @@ class ServiceManager {
.then(function (app) {
appFound = app;
if (!appFound) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'App name not found!');
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "App name not found!");
}
return self.createPreDeployFunctionIfExist(app);
})
.then(function (preDeployFunction) {
if (!appFound) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'App name not found!');
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "App name not found!");
}
return dockerApi
.updateService(serviceName, null, appFound.volumes, appFound.networks, appFound.envVars, null, dockerAuthObject, Number(appFound.instanceCount), appFound.nodeId, dataStore.getNameSpace(), appFound.ports, appFound, preDeployFunction);
.updateService(serviceName, undefined, appFound.volumes, appFound.networks, appFound.envVars, undefined, dockerAuthObject, Number(appFound.instanceCount), appFound.nodeId, dataStore.getNameSpace(), appFound.ports, appFound, preDeployFunction);
});
}
reloadLoadBalancer() {
Logger.d('Updating Load Balancer');
Logger.d("Updating Load Balancer");
const self = this;
return self.loadBalancerManager.rePopulateNginxConfigFile(self.dataStore)
.then(function () {
Logger.d('sendReloadSignal...');
Logger.d("sendReloadSignal...");
return self.loadBalancerManager.sendReloadSignal();
});
}
File diff suppressed because one or more lines are too long
+13
View File
@@ -97,6 +97,11 @@
"@types/tough-cookie": "*"
}
},
"@types/require-from-string": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@types/require-from-string/-/require-from-string-1.2.0.tgz",
"integrity": "sha512-5vE9WoOOC9/DoD3Zj53UISpM+5tSvh8k0mL4fe2zFI6vO715/W4IQ3EdVUrWVMrFi1/NZhyMvm2iKsDFkEGddQ=="
},
"@types/ssh2": {
"version": "0.5.36",
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-0.5.36.tgz",
@@ -115,6 +120,14 @@
"@types/node": "*"
}
},
"@types/tar": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/tar/-/tar-4.0.0.tgz",
"integrity": "sha512-YybbEHNngcHlIWVCYsoj7Oo1JU9JqONuAlt1LlTH/lmL8BMhbzdFUgReY87a05rY1j8mfK47Del+TCkaLAXwLw==",
"requires": {
"@types/node": "*"
}
},
"@types/tough-cookie": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.4.tgz",
+2
View File
@@ -13,7 +13,9 @@
"@types/fs-extra": "^5.0.4",
"@types/jsonwebtoken": "^8.3.0",
"@types/request": "^2.48.1",
"@types/require-from-string": "^1.2.0",
"@types/ssh2": "^0.5.36",
"@types/tar": "^4.0.0",
"@types/uuid": "^3.4.4",
"bcryptjs": "^2.4.3",
"body-parser": "^1.18.3",
+11 -11
View File
@@ -259,16 +259,8 @@ class Authenticator {
);
});
}
}
interface IHash {
[details: string]: Authenticator;
}
const authenticatorCache: IHash = {};
exports = {
get: function(namespace: string): Authenticator | undefined {
static get(namespace: string): Authenticator|undefined {
if (!namespace) {
return undefined;
}
@@ -285,5 +277,13 @@ exports = {
}
return authenticatorCache[namespace];
},
};
}
}
interface IHash {
[details: string]: Authenticator;
}
const authenticatorCache: IHash = {};
export = Authenticator;
+1 -1
View File
@@ -875,7 +875,7 @@ class CaptainManager {
*
* @returns {Promise.<boolean>}
*/
verifyCaptainOwnsDomainOrThrow(domainName: string, identifierSuffix: string) {
verifyCaptainOwnsDomainOrThrow(domainName: string, identifierSuffix: string|undefined) {
const self = this;
const randomUuid = uuid();
@@ -1,50 +1,55 @@
const CaptainConstants = require('../utils/CaptainConstants');
const Logger = require('../utils/Logger');
const fs = require('fs-extra');
const tar = require('tar');
const path = require('path');
const CaptainManager = require('./CaptainManager');
const ApiStatusCodes = require('../api/ApiStatusCodes');
const TemplateHelper = require('./TemplateHelper');
const Authenticator = require('./Authenticator');
const GitHelper = require('../utils/GitHelper');
const uuid = require('uuid/v4');
const requireFromString = require('require-from-string');
import CaptainConstants = require("../utils/CaptainConstants");
import Logger = require("../utils/Logger");
import fs = require("fs-extra");
import tar = require("tar");
import path = require("path");
import CaptainManager = require("./CaptainManager");
import LoadBalancerManager = require("./LoadBalancerManager");
import DockerApi = require("../docker/DockerApi");
import DataStore = require("../datastore/DataStoreImpl");
import ApiStatusCodes = require("../api/ApiStatusCodes");
import TemplateHelper = require("./TemplateHelper");
import Authenticator = require("./Authenticator");
import GitHelper = require("../utils/GitHelper");
import uuid = require("uuid/v4");
import requireFromString = require("require-from-string");
const BUILD_LOG_SIZE = 50;
const SOURCE_FOLDER_NAME = 'src';
const DOCKER_FILE = 'Dockerfile';
const CAPTAIN_DEFINITION_FILE = 'captain-definition';
const PLACEHOLDER_DOCKER_FILE_CONTENT = 'FROM ' + CaptainConstants.appPlaceholderImageName +
const SOURCE_FOLDER_NAME = "src";
const DOCKER_FILE = "Dockerfile";
const CAPTAIN_DEFINITION_FILE = "captain-definition";
const PLACEHOLDER_DOCKER_FILE_CONTENT = "FROM " + CaptainConstants.appPlaceholderImageName +
'\nCMD [ "npm", "start" ]';
function getRawImageSourceFolder(imageName, newVersionPulled) {
return CaptainConstants.captainRawImagesDir + '/' + imageName + '/' + newVersionPulled + '/' + SOURCE_FOLDER_NAME;
function getRawImageSourceFolder(imageName: string, newVersionPulled: string) {
return CaptainConstants.captainRawImagesDir + "/" + imageName + "/" + newVersionPulled + "/" + SOURCE_FOLDER_NAME;
}
function getRawImageBaseFolder(imageName, newVersionPulled) {
return CaptainConstants.captainRawImagesDir + '/' + imageName + '/' + newVersionPulled;
function getRawImageBaseFolder(imageName: string, newVersionPulled: string) {
return CaptainConstants.captainRawImagesDir + "/" + imageName + "/" + newVersionPulled;
}
function getTarImageBaseFolder(imageName, newVersionPulled) {
return CaptainConstants.captainTarImagesDir + '/' + imageName + '/' + newVersionPulled;
function getTarImageBaseFolder(imageName: string, newVersionPulled: string) {
return CaptainConstants.captainTarImagesDir + "/" + imageName + "/" + newVersionPulled;
}
function getCaptainDefinitionTempFolder(serviceName, randomSuffix) {
return CaptainConstants.captainDefinitionTempDir + '/' + serviceName + '/' + randomSuffix;
function getCaptainDefinitionTempFolder(serviceName: string, randomSuffix: string) {
return CaptainConstants.captainDefinitionTempDir + "/" + serviceName + "/" + randomSuffix;
}
class BuildLog {
constructor(size) {
this.size = size;
private isBuildFailed: boolean;
private firstLineNumber: number;
private lines: string[];
constructor(private size: number) {
this.clear();
}
onBuildFailed(error) {
this.log('----------------------');
this.log('Deploy failed!');
onBuildFailed(error: string) {
this.log("----------------------");
this.log("Deploy failed!");
this.log(error);
this.isBuildFailed = true;
}
@@ -54,12 +59,12 @@ class BuildLog {
this.firstLineNumber = -this.size;
this.lines = [];
for (let i = 0; i < this.size; i++) {
this.lines.push('');
this.lines.push("");
}
}
log(msg) {
msg = (msg || '') + '';
log(msg: string) {
msg = (msg || "") + "";
this.lines.shift();
this.lines.push(msg);
this.firstLineNumber++;
@@ -79,7 +84,12 @@ class BuildLog {
class ServiceManager {
constructor(user, dockerApi, loadBalancerManager) {
private dataStore: DataStore;
private activeBuilds: any;
private buildLogs: any;
private isReady: boolean;
constructor(private user: any, private dockerApi: DockerApi, private loadBalancerManager: LoadBalancerManager) {
this.user = user;
this.dataStore = user.dataStore;
this.dockerApi = dockerApi;
@@ -95,17 +105,17 @@ class ServiceManager {
return this.isReady;
}
createTarFarFromCaptainContent(captainDefinitionContent, appName, tarDestination) {
createTarFarFromCaptainContent(captainDefinitionContent: string, appName: string, tarDestination: string) {
let serviceName = this.dataStore.getServiceName(appName);
const serviceName = this.dataStore.getServiceName(appName);
let captainDefinitionDirPath;
let captainDefinitionDirPath: string| undefined = undefined;
return Promise.resolve()
.then(function () {
for (let i = 0; i < 100; i++) {
let temp = getCaptainDefinitionTempFolder(serviceName, uuid());
const temp = getCaptainDefinitionTempFolder(serviceName, uuid());
if (!fs.pathExistsSync(temp)) {
captainDefinitionDirPath = temp;
break;
@@ -116,7 +126,7 @@ class ServiceManager {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Cannot create a temp file! Something is seriously wrong with the temp folder");
}
return fs.outputFile(captainDefinitionDirPath + '/' + CAPTAIN_DEFINITION_FILE, captainDefinitionContent);
return fs.outputFile(captainDefinitionDirPath + "/" + CAPTAIN_DEFINITION_FILE, captainDefinitionContent);
})
.then(function () {
@@ -129,6 +139,10 @@ class ServiceManager {
})
.then(function () {
if (!captainDefinitionDirPath) {
throw new Error("captainDefinitionDirPath is NULL");
}
return fs.remove(captainDefinitionDirPath);
});
@@ -144,28 +158,28 @@ class ServiceManager {
* @param gitHash
* @returns {Promise<void>}
*/
createImage(appName, source, gitHash) {
createImage(appName: string, source: any, gitHash: string) {
Logger.d('Creating image for: ' + appName);
Logger.d("Creating image for: " + appName);
const self = this;
let imageName = this.dataStore.getImageName(CaptainManager.get().getDockerAuthObject(), appName);
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
let newVersion = null;
let rawImageSourceFolder = null;
let rawImageBaseFolder = null;
let tarImageBaseFolder = null;
let tarballFilePath = null;
let dockerFilePath = null;
const imageName = this.dataStore.getImageName(CaptainManager.get().getDockerAuthObject(), appName);
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
let newVersion: number;
let rawImageSourceFolder: string;
let rawImageBaseFolder: string;
let tarImageBaseFolder: string;
let tarballFilePath: string;
let dockerFilePath: string;
this.activeBuilds[appName] = true;
this.buildLogs[appName] = this.buildLogs[appName] || new BuildLog(BUILD_LOG_SIZE);
this.buildLogs[appName].clear();
this.buildLogs[appName].log('------------------------- ' + (new Date()));
this.buildLogs[appName].log('Build started for ' + appName);
this.buildLogs[appName].log("------------------------- " + (new Date()));
this.buildLogs[appName].log("Build started for " + appName);
return Promise.resolve()
.then(function () {
@@ -179,20 +193,20 @@ class ServiceManager {
rawImageSourceFolder = getRawImageSourceFolder(imageName, newVersionPulled);
rawImageBaseFolder = getRawImageBaseFolder(imageName, newVersionPulled);
dockerFilePath = rawImageBaseFolder + '/' + DOCKER_FILE;
dockerFilePath = rawImageBaseFolder + "/" + DOCKER_FILE;
tarImageBaseFolder = getTarImageBaseFolder(imageName, newVersionPulled);
tarballFilePath = tarImageBaseFolder + '/image.tar';
tarballFilePath = tarImageBaseFolder + "/image.tar";
return fs.ensureDir(rawImageSourceFolder)
.then(function () {
return rawImageSourceFolder
return rawImageSourceFolder;
});
})
.then(function (rawImageSourceFolder) {
let promiseToFetchDirectory = null;
let promiseToFetchDirectory: Promise<string>;
if (source.pathToSrcTarballFile) {
promiseToFetchDirectory = tar
@@ -204,7 +218,7 @@ class ServiceManager {
return gitHash;
});
} else if (source.repoInfo) {
let repoInfo = source.repoInfo;
const repoInfo = source.repoInfo;
promiseToFetchDirectory = GitHelper
.clone(repoInfo.user, repoInfo.password, repoInfo.repo, repoInfo.branch, rawImageSourceFolder)
.then(function () {
@@ -222,14 +236,14 @@ class ServiceManager {
})
.then(function () {
return fs.pathExists(rawImageSourceFolder + '/' + CAPTAIN_DEFINITION_FILE)
return fs.pathExists(rawImageSourceFolder + "/" + CAPTAIN_DEFINITION_FILE);
})
.then(function (exists) {
if (!exists) {
Logger.d('Captain Definition does not exist in the base tar. Looking inside...');
Logger.d("Captain Definition does not exist in the base tar. Looking inside...");
// check if there is only one child
// check if it's a directory
@@ -238,7 +252,7 @@ class ServiceManager {
// move the child directory out to base and rename it to rawImageSourceFolder
// read captain definition from the folder and return it.
let directoryInside = null;
let directoryInside: string;
return new Promise(
function (resolve, reject) {
@@ -259,7 +273,7 @@ class ServiceManager {
});
})
.then(function (directory) {
.then(function (directory: string) {
directoryInside = directory;
@@ -272,7 +286,7 @@ class ServiceManager {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Captain Definition file does not exist!");
}
const BAK = '.bak';
const BAK = ".bak";
fs.renameSync(rawImageSourceFolder, rawImageSourceFolder + BAK);
fs.renameSync(path.join(rawImageSourceFolder + BAK, directoryInside), rawImageSourceFolder);
@@ -282,7 +296,7 @@ class ServiceManager {
})
.then(function () {
return fs.readJson(rawImageSourceFolder + '/' + CAPTAIN_DEFINITION_FILE);
return fs.readJson(rawImageSourceFolder + "/" + CAPTAIN_DEFINITION_FILE);
})
.then(function (data) {
@@ -297,13 +311,13 @@ class ServiceManager {
if (data.schemaVersion === 1) {
let templateIdTag = data.templateId;
let dockerfileLines = data.dockerfileLines;
let hasDockerfileLines = dockerfileLines && dockerfileLines.length > 0;
const templateIdTag = data.templateId;
const dockerfileLines = data.dockerfileLines;
const hasDockerfileLines = dockerfileLines && dockerfileLines.length > 0;
if (hasDockerfileLines && !templateIdTag) {
return dockerfileLines.join('\n');
return dockerfileLines.join("\n");
} else if (!hasDockerfileLines && templateIdTag) {
@@ -345,14 +359,14 @@ class ServiceManager {
return dockerApi
.buildImageFromDockerFile(imageName, newVersion, tarballFilePath, self.buildLogs[appName])
.catch(function (error) {
throw ApiStatusCodes.createError(ApiStatusCodes.BUILD_ERROR, ('' + error).trim());
})
.catch(function (error: any) {
throw ApiStatusCodes.createError(ApiStatusCodes.BUILD_ERROR, ("" + error).trim());
});
})
.then(function () {
Logger.d('Cleaning up up the files... ' + tarImageBaseFolder + ' and ' + rawImageBaseFolder);
Logger.d("Cleaning up up the files... " + tarImageBaseFolder + " and " + rawImageBaseFolder);
return fs.remove(tarImageBaseFolder);
@@ -364,23 +378,23 @@ class ServiceManager {
})
.then(function () {
let authObj = CaptainManager.get().getDockerAuthObject();
const authObj = CaptainManager.get().getDockerAuthObject();
if (!authObj) {
Logger.d('No Docker Auth is found. Skipping pushing the image.');
Logger.d("No Docker Auth is found. Skipping pushing the image.");
return true;
}
Logger.d('Docker Auth is found. Pushing the image...');
Logger.d("Docker Auth is found. Pushing the image...");
return dockerApi
.pushImage(imageName, newVersion, authObj, self.buildLogs[appName])
.catch(function (error) {
return new Promise(function (resolve, reject) {
Logger.e('PUSH FAILED');
Logger.e("PUSH FAILED");
Logger.e(error);
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'Push failed: ' + error));
})
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Push failed: " + error));
});
});
})
@@ -392,29 +406,29 @@ class ServiceManager {
self.activeBuilds[appName] = false;
return new Promise(function (resolve, reject) {
reject(error);
})
});
});
}
enableCustomDomainSsl(appName, customDomain) {
enableCustomDomainSsl(appName: string, customDomain: string) {
const self = this;
return Promise.resolve()
.then(function () {
Logger.d('Verifying Captain owns domain: ' + customDomain);
Logger.d("Verifying Captain owns domain: " + customDomain);
return CaptainManager.get().verifyCaptainOwnsDomainOrThrow(customDomain);
return CaptainManager.get().verifyCaptainOwnsDomainOrThrow(customDomain, undefined);
})
.then(function () {
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
Logger.d('Enabling SSL for: ' + appName + ' on ' + customDomain);
Logger.d("Enabling SSL for: " + appName + " on " + customDomain);
return self.dataStore.getAppsDataStore().verifyCustomDomainBelongsToApp(appName, customDomain);
@@ -436,27 +450,27 @@ class ServiceManager {
});
}
addCustomDomain(appName, customDomain) {
addCustomDomain(appName: string, customDomain: string) {
const self = this;
return Promise.resolve()
.then(function () {
let rootDomain = self.dataStore.getRootDomain();
let dotRootDomain = "." + rootDomain;
const rootDomain = self.dataStore.getRootDomain();
const dotRootDomain = "." + rootDomain;
if (!customDomain || !(/^[a-z0-9\-\.]+$/.test(customDomain))) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME,
'Domain name is not accepted. Please use alphanumerical domains such as myapp.google123.ca');
"Domain name is not accepted. Please use alphanumerical domains such as myapp.google123.ca");
}
if (customDomain.length > 80) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME,
'Domain name is not accepted. Please use alphanumerical domains less than 80 characters in length.');
"Domain name is not accepted. Please use alphanumerical domains less than 80 characters in length.");
}
if (customDomain.indexOf('..') >= 0) {
if (customDomain.indexOf("..") >= 0) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME,
'Domain name is not accepted. You cannot have two consecutive periods ".." inside a domain name. Please use alphanumerical domains such as myapp.google123.ca');
}
@@ -464,7 +478,7 @@ class ServiceManager {
if (customDomain.indexOf(dotRootDomain) >= 0 &&
(customDomain.indexOf(dotRootDomain) + dotRootDomain.length) === customDomain.length) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_BAD_NAME,
'Domain name is not accepted. Custom domain cannot be subdomain of root domain.');
"Domain name is not accepted. Custom domain cannot be subdomain of root domain.");
}
@@ -477,10 +491,10 @@ class ServiceManager {
.then(function () {
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
Logger.d('Enabling custom domain for: ' + appName);
Logger.d("Enabling custom domain for: " + appName);
return self.dataStore.getAppsDataStore().addCustomDomainForApp(appName, customDomain);
@@ -492,17 +506,17 @@ class ServiceManager {
});
}
removeCustomDomain(appName, customDomain) {
removeCustomDomain(appName: string, customDomain: string) {
const self = this;
return Promise.resolve()
.then(function () {
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
Logger.d('Removing custom domain for: ' + appName);
Logger.d("Removing custom domain for: " + appName);
return self.dataStore.getAppsDataStore().removeCustomDomainForApp(appName, customDomain);
@@ -514,12 +528,11 @@ class ServiceManager {
});
}
enableSslForApp(appName) {
enableSslForApp(appName: string) {
const self = this;
let rootDomain = null;
let app = null;
let rootDomain: string;
return Promise.resolve()
.then(function () {
@@ -529,10 +542,10 @@ class ServiceManager {
})
.then(function () {
Logger.d('Enabling SSL for: ' + appName);
Logger.d("Enabling SSL for: " + appName);
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
return self.dataStore.getRootDomain();
@@ -543,7 +556,7 @@ class ServiceManager {
rootDomain = val;
if (!rootDomain) {
throw new Error('No rootDomain! Cannot verify domain');
throw new Error("No rootDomain! Cannot verify domain");
}
})
@@ -555,7 +568,7 @@ class ServiceManager {
})
.then(function () {
return appName + '.' + rootDomain;
return appName + "." + rootDomain;
})
.then(function (domainName) {
@@ -575,17 +588,17 @@ class ServiceManager {
});
}
verifyCaptainOwnsGenericSubDomain(appName) {
verifyCaptainOwnsGenericSubDomain(appName: string) {
const self = this;
let rootDomain = null;
let rootDomain: string;
return Promise.resolve()
.then(function () {
if (!appName) {
throw new Error('No App Name! Cannot verify domain');
throw new Error("No App Name! Cannot verify domain");
}
return self.dataStore.getRootDomain();
@@ -604,30 +617,30 @@ class ServiceManager {
})
.then(function () {
return appName + '.' + rootDomain;
return appName + "." + rootDomain;
})
.then(function (domainName) {
Logger.d('Verifying Captain owns domain: ' + domainName);
Logger.d("Verifying Captain owns domain: " + domainName);
return CaptainManager.get().verifyCaptainOwnsDomainOrThrow(domainName);
return CaptainManager.get().verifyCaptainOwnsDomainOrThrow(domainName, undefined);
});
}
removeApp(appName) {
Logger.d('Removing service for: ' + appName);
removeApp(appName: string) {
Logger.d("Removing service for: " + appName);
const self = this;
let serviceName = this.dataStore.getServiceName(appName);
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
const serviceName = this.dataStore.getServiceName(appName);
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
return Promise.resolve()
.then(function () {
Logger.d('Check if service is running: ' + serviceName);
Logger.d("Check if service is running: " + serviceName);
return dockerApi
.isServiceRunningByName(serviceName);
@@ -637,7 +650,7 @@ class ServiceManager {
return dockerApi
.removeService(serviceName);
} else {
Logger.w('Cannot delete service... It is not running: ' + serviceName);
Logger.w("Cannot delete service... It is not running: " + serviceName);
return true;
}
@@ -654,13 +667,13 @@ class ServiceManager {
});
}
getUnusedImages(mostRecentLimit) {
Logger.d('Getting unused images, excluding most recent ones: ' + mostRecentLimit);
getUnusedImages(mostRecentLimit: number) {
Logger.d("Getting unused images, excluding most recent ones: " + mostRecentLimit);
const self = this;
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
let allImages = null;
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
let allImages: any[];
return Promise.resolve()
.then(function () {
@@ -672,11 +685,11 @@ class ServiceManager {
allImages = images;
return dataStore.getAppsDataStore().getAppDefinitions()
return dataStore.getAppsDataStore().getAppDefinitions();
})
.then(function (apps) {
let unusedImages = [];
const unusedImages = [];
for (let i = 0; i < allImages.length; i++) {
const img = allImages[i];
@@ -685,7 +698,7 @@ class ServiceManager {
for (let j = 0; j < img.RepoTags.length; j++) {
const repoTag = img.RepoTags[j];
Object.keys(apps).forEach(function (key, index) {
let app = apps[key];
const app = apps[key];
app.appName = key;
for (let k = 0; k < (mostRecentLimit + 1); k++) {
if (repoTag.indexOf(dataStore.getImageNameWithoutAuthObj(app.appName, Number(app.deployedVersion) - k)) >= 0) {
@@ -699,8 +712,8 @@ class ServiceManager {
if (!imageInUse) {
unusedImages.push({
id: img.Id,
description: (img.RepoTags && img.RepoTags.length) ? img.RepoTags[0] : 'untagged'
})
description: (img.RepoTags && img.RepoTags.length) ? img.RepoTags[0] : "untagged"
});
}
}
@@ -709,14 +722,12 @@ class ServiceManager {
});
}
deleteImages(imageIds) {
deleteImages(imageIds: string[]) {
Logger.d('Deleting images...');
Logger.d("Deleting images...");
const self = this;
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
let allImages = null;
const dockerApi = this.dockerApi;
return Promise.resolve()
.then(function () {
@@ -726,17 +737,17 @@ class ServiceManager {
});
}
ensureServiceInitedAndUpdated(appName, version) {
ensureServiceInitedAndUpdated(appName: string, version: number) {
Logger.d('Ensure service inited and Updated for: ' + appName);
Logger.d("Ensure service inited and Updated for: " + appName);
const self = this;
let serviceName = this.dataStore.getServiceName(appName);
const serviceName = this.dataStore.getServiceName(appName);
const dockerAuthObject = CaptainManager.get().getDockerAuthObject();
let imageName = this.dataStore.getImageName(dockerAuthObject, appName, version);
let dockerApi = this.dockerApi;
let dataStore = this.dataStore;
let app = null;
const imageName = this.dataStore.getImageName(dockerAuthObject, appName, version);
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
let app: any;
return dataStore.getAppsDataStore().setDeployedVersion(appName, version)
.then(function () {
@@ -745,20 +756,20 @@ class ServiceManager {
.then(function (appFound) {
app = appFound;
Logger.d('Check if service is running: ' + serviceName);
Logger.d("Check if service is running: " + serviceName);
return dockerApi
.isServiceRunningByName(serviceName);
})
.then(function (isRunning) {
if (isRunning) {
Logger.d('Service is already running: ' + serviceName);
Logger.d("Service is already running: " + serviceName);
return true;
} else {
Logger.d('Creating service: ' + serviceName + ' with image: ' + imageName);
Logger.d("Creating service: " + serviceName + " with image: " + imageName);
// if we pass in networks here. Almost always it results in a delayed update which causes
// update errors if they happen right away!
return dockerApi
.createServiceOnNodeId(imageName, serviceName);
.createServiceOnNodeId(imageName, serviceName, undefined, undefined, undefined, undefined, undefined);
}
})
.then(function () {
@@ -768,12 +779,11 @@ class ServiceManager {
})
.then(function (preDeployFunction) {
Logger.d('Updating service: ' + serviceName + ' with image: ' + imageName);
Logger.d("Updating service: " + serviceName + " with image: " + imageName);
return dockerApi
.updateService(serviceName, imageName, app.volumes, app.networks, app.envVars, null,
dockerAuthObject, Number(app.instanceCount), app.nodeId, dataStore.getNameSpace(),
app, preDeployFunction);
return dockerApi.updateService(serviceName, imageName, app.volumes, app.networks, app.envVars,
undefined, dockerAuthObject, Number(app.instanceCount), app.nodeId,
dataStore.getNameSpace(), undefined, app, preDeployFunction);
})
.then(function () {
@@ -788,12 +798,12 @@ class ServiceManager {
});
}
createPreDeployFunctionIfExist(app) {
createPreDeployFunctionIfExist(app: any) {
let preDeployFunction = app.preDeployFunction;
if (!preDeployFunction) {
return null;
return undefined;
}
/*
@@ -811,20 +821,22 @@ class ServiceManager {
};
*/
preDeployFunction = preDeployFunction + '\n\n module.exports = preDeployFunction';
preDeployFunction = preDeployFunction + "\n\n module.exports = preDeployFunction";
return requireFromString(preDeployFunction);
}
updateAppDefinition(appName, instanceCount, envVars, volumes, nodeId, notExposeAsWebApp, forceSsl, ports, appPushWebhook, customNginxConfig, preDeployFunction) {
updateAppDefinition(appName: string, instanceCount: number, envVars: any[], volumes: any[],
nodeId: string, notExposeAsWebApp: boolean, forceSsl: boolean, ports: any[],
appPushWebhook: any , customNginxConfig: string, preDeployFunction: string) {
const self = this;
const dataStore = this.dataStore;
const dockerApi = this.dockerApi;
let serviceName = null;
let serviceName: string;
let checkIfNodeIdExists = function (nodeIdToCheck) {
const checkIfNodeIdExists = function (nodeIdToCheck: string) {
return dockerApi
.getNodesInfo()
.then(function (nodeInfo) {
@@ -867,14 +879,14 @@ class ServiceManager {
return dockerApi
.isServiceRunningByName(serviceName)
.then(function (isRunning) {
.then(function (isRunning: boolean) {
if (!isRunning) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "Cannot find the service. Try again in a minute...");
}
return dockerApi
.getNodeIdByServiceName(serviceName);
})
.then(function (nodeIdRunningService) {
.then(function (nodeIdRunningService: string) {
if (!nodeIdRunningService) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "No NodeId was found. Try again in a minute...");
}
@@ -901,7 +913,8 @@ class ServiceManager {
.then(function () {
return dataStore.getAppsDataStore().updateAppDefinitionInDb(appName, instanceCount, envVars, volumes, nodeId,
notExposeAsWebApp, forceSsl, ports, appPushWebhook, Authenticator.get(dataStore.getNameSpace()),
notExposeAsWebApp, forceSsl, ports,
appPushWebhook, Authenticator.get(dataStore.getNameSpace()),
customNginxConfig, preDeployFunction);
})
@@ -913,7 +926,7 @@ class ServiceManager {
});
}
isAppBuilding(appName) {
isAppBuilding(appName: string) {
return !!this.activeBuilds[appName];
}
@@ -923,18 +936,18 @@ class ServiceManager {
*/
isAnyBuildRunning() {
let activeBuilds = this.activeBuilds;
const activeBuilds = this.activeBuilds;
for (let appName in activeBuilds) {
for (const appName in activeBuilds) {
if (!!activeBuilds[appName]) {
return appName;
}
}
return null;
return undefined;
}
getBuildStatus(appName) {
getBuildStatus(appName: string) {
const self = this;
this.buildLogs[appName] = this.buildLogs[appName] || new BuildLog(BUILD_LOG_SIZE);
@@ -942,24 +955,24 @@ class ServiceManager {
isAppBuilding: self.isAppBuilding(appName),
logs: self.buildLogs[appName].getLogs(),
isBuildFailed: self.buildLogs[appName].isBuildFailed
}
};
}
logBuildFailed(appName, error) {
error = (error || '') + '';
logBuildFailed(appName: string, error: string) {
error = (error || "") + "";
this.buildLogs[appName] = this.buildLogs[appName] || new BuildLog(BUILD_LOG_SIZE);
this.buildLogs[appName].onBuildFailed(error);
}
updateServiceOnDefinitionUpdate(appName) {
updateServiceOnDefinitionUpdate(appName: string) {
const self = this;
let serviceName = this.dataStore.getServiceName(appName);
const serviceName = this.dataStore.getServiceName(appName);
const dockerAuthObject = CaptainManager.get().getDockerAuthObject();
const dataStore = this.dataStore;
const dockerApi = this.dockerApi;
let appFound = null;
let appFound: any;
return Promise.resolve()
.then(function () {
@@ -970,7 +983,7 @@ class ServiceManager {
appFound = app;
if (!appFound) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'App name not found!');
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "App name not found!");
}
return self.createPreDeployFunctionIfExist(app);
@@ -979,11 +992,11 @@ class ServiceManager {
.then(function (preDeployFunction) {
if (!appFound) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'App name not found!');
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, "App name not found!");
}
return dockerApi
.updateService(serviceName, null, appFound.volumes, appFound.networks, appFound.envVars, null,
.updateService(serviceName, undefined, appFound.volumes, appFound.networks, appFound.envVars, undefined,
dockerAuthObject, Number(appFound.instanceCount), appFound.nodeId, dataStore.getNameSpace(),
appFound.ports, appFound, preDeployFunction);
});
@@ -992,11 +1005,11 @@ class ServiceManager {
reloadLoadBalancer() {
Logger.d('Updating Load Balancer');
Logger.d("Updating Load Balancer");
const self = this;
return self.loadBalancerManager.rePopulateNginxConfigFile(self.dataStore)
.then(function () {
Logger.d('sendReloadSignal...');
Logger.d("sendReloadSignal...");
return self.loadBalancerManager.sendReloadSignal();
});
}