Reorganized directories

This commit is contained in:
Kasra Bigdeli
2018-12-05 22:15:23 -08:00
parent d210656aff
commit d9bfa9bb4b
36 changed files with 1708 additions and 56 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ const logger = require("morgan");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const httpProxyImport = require("http-proxy");
const CaptainManager = require("./user/CaptainManager");
const CaptainManager = require("./user/system/CaptainManager");
const BaseApi = require("./api/BaseApi");
const ApiStatusCodes = require("./api/ApiStatusCodes");
const Injector = require("./injection/Injector");
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
const DataStoreProvider = require("../datastore/DataStoreProvider");
const Authenticator = require("../user/Authenticator");
const CaptainConstants = require("../utils/CaptainConstants");
const CaptainManager = require("../user/CaptainManager");
const CaptainManager = require("../user/system/CaptainManager");
const ServiceManager = require("../user/ServiceManager");
const DockerApiProvider = require("../docker/DockerApi");
const BaseApi = require("../api/BaseApi");
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"Injector.js","sourceRoot":"","sources":["../../src/injection/Injector.ts"],"names":[],"mappings":";;AAAA,oEAAoE;AACpE,uDAAuD;AACvD,8DAA8D;AAC9D,yDAAyD;AACzD,yDAAyD;AACzD,yDAAyD;AACzD,0CAA0C;AAE1C,0CAA0C;AAG1C,2DAA2D;AAC3D,wDAAwD;AAExD,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,EAAE,CAAA;AAEzC,MAAM,kBAAkB,GAAG,EAAqC,CAAA;AAEhE;;GAEG;AACH,SAAgB,YAAY;IACxB,OAAO,UAAS,GAAY,EAAE,GAAa,EAAE,IAAkB;QAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAA;QAEzB,MAAM,CAAC,WAAW,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,CAAA;QACzD,MAAM,CAAC,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAA;QAC/D,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAC,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAA;QAEzD,IACI,MAAM,CAAC,SAAS;YAChB,MAAM,CAAC,SAAS,KAAK,gBAAgB,CAAC,aAAa,EACrD;YACE,MAAM,cAAc,CAAC,WAAW,CAC5B,cAAc,CAAC,oBAAoB,EACnC,mBAAmB,CACtB,CAAA;SACJ;QAED,IAAI,EAAE,CAAA;IACV,CAAC,CAAA;AACL,CAAC;AApBD,oCAoBC;AAED;;GAEG;AACH,SAAgB,UAAU;IACtB,OAAO,UAAS,GAAY,EAAE,GAAa,EAAE,IAAkB;QAC3D,IAAI,kBAAkB,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;YACtD,IAAI,EAAE,CAAA;YACN,OAAM,CAAC,4CAA4C;SACtD;QAED,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAA;QAEtC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;aACvB,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;aAC9D,IAAI,CAAC,UAAS,WAAW;YACtB,IAAI,WAAW,EAAE;gBACb,MAAM,SAAS,GAAG,iBAAiB,CAAC,YAAY,CAAC,SAAS,CAAC,CAAA;gBAC3D,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,EAAE;oBAChC,kBAAkB,CAAC,SAAS,CAAC,GAAG,IAAI,cAAc,CAC9C,SAAS,EACT,SAAS,EACT,cAAc,CAAC,GAAG,EAAE,CAAC,qBAAqB,EAAE,CAC/C,CAAA;iBACJ;gBACD,MAAM,IAAI,GAA2B;oBACjC,SAAS,EAAE,SAAS;oBACpB,SAAS,EAAE,SAAS;oBACpB,cAAc,EAAE,kBAAkB,CAAC,SAAS,CAAC;oBAC7C,WAAW,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;iBACxD,CAAA;gBACD,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAA;aACzB;YAED,IAAI,EAAE,CAAA;QACV,CAAC,CAAC;aACD,KAAK,CAAC,UAAS,KAAmB;YAC/B,IAAI,KAAK,IAAI,KAAK,CAAC,gBAAgB,EAAE;gBACjC,GAAG,CAAC,IAAI,CACJ,IAAI,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,UAAU,CAAC,CACxD,CAAA;gBACD,OAAM;aACT;YACD,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YACf,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,SAAS,CAAA;YAC3B,IAAI,EAAE,CAAA;QACV,CAAC,CAAC,CAAA;IACV,CAAC,CAAA;AACL,CAAC;AA5CD,gCA4CC;AAED;;GAEG;AACH,SAAgB,oBAAoB;IAChC,OAAO,UAAS,GAAY,EAAE,GAAa,EAAE,IAAkB;QAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAA;QAC7B,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAA;QACrC,IAAI,GAAG,GAAG,SAAS,CAAA;QAEnB,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE;YACtB,MAAM,CAAC,CAAC,CAAC,iDAAiD,CAAC,CAAA;YAC3D,IAAI,EAAE,CAAA;YACN,OAAM;SACT;QAED,MAAM,SAAS,GAAG,iBAAiB,CAAC,YAAY,CAAC,SAAS,CAAC,CAAA;QAE3D,IAAI,WAAuC,CAAA;QAE3C,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;aACvB,yBAAyB,CAAC,KAAK,CAAC;aAChC,IAAI,CAAC,UAAS,IAAI;YACf,WAAW,GAAG,IAAI,CAAA;YAElB,OAAO,SAAS;iBACX,gBAAgB,EAAE;iBAClB,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;QAC9C,CAAC,CAAC;aACD,IAAI,CAAC,UAAS,QAAQ;YACnB,GAAG,GAAG,QAAQ,CAAA;YAEd,IACI,GAAG,CAAC,cAAc;gBAClB,GAAG,CAAC,cAAc,CAAC,YAAY,KAAK,WAAW,CAAC,YAAY,EAC9D;gBACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAA;aAC7C;YAED,MAAM,SAAS,GAAG,iBAAiB,CAAC,YAAY,CAAC,SAAS,CAAC,CAAA;YAE3D,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,EAAE;gBAChC,kBAAkB,CAAC,SAAS,CAAC,GAAG,IAAI,cAAc,CAC9C,SAAS,EACT,SAAS,EACT,cAAc,CAAC,GAAG,EAAE,CAAC,qBAAqB,EAAE,CAC/C,CAAA;aACJ;YAED,MAAM,IAAI,GAA2B;gBACjC,SAAS,EAAE,SAAS;gBACpB,SAAS,EAAE,SAAS;gBACpB,cAAc,EAAE,kBAAkB,CAAC,SAAS,CAAC;gBAC7C,WAAW,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;aACxD,CAAA;YAED,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAA;YACtB,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,CAAA;YACpB,GAAG,CAAC,MAAM,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO,CAAA;YAExC,IAAI,EAAE,CAAA;QACV,CAAC,CAAC;aACD,KAAK,CAAC,UAAS,KAAK;YACjB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YACf,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,SAAS,CAAA;YAC1B,IAAI,EAAE,CAAA;QACV,CAAC,CAAC,CAAA;IACV,CAAC,CAAA;AACL,CAAC;AAhED,oDAgEC;AAED;;;GAGG;AACH,SAAgB,6BAA6B;IACzC,OAAO,UAAS,GAAY,EAAE,GAAa,EAAE,IAAkB;QAC3D,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,aAAa,CAAC;aAC5C,0BAA0B,CACvB,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CACjD;aACA,IAAI,CAAC,UAAS,IAAI;YACf,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAA;YAEtB,IAAI,EAAE,CAAA;QACV,CAAC,CAAC;aACD,KAAK,CAAC,UAAS,KAAK;YACjB,IAAI,KAAK,IAAI,KAAK,CAAC,gBAAgB,EAAE;gBACjC,GAAG,CAAC,IAAI,CACJ,IAAI,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,UAAU,CAAC,CACxD,CAAA;gBACD,OAAM;aACT;YACD,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YACf,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,SAAS,CAAA;YAC3B,IAAI,EAAE,CAAA;QACV,CAAC,CAAC,CAAA;IACV,CAAC,CAAA;AACL,CAAC;AAvBD,sEAuBC"}
{"version":3,"file":"Injector.js","sourceRoot":"","sources":["../../src/injection/Injector.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ const express = require("express");
const BaseApi = require("../../api/BaseApi");
const ApiStatusCodes = require("../../api/ApiStatusCodes");
const Logger = require("../../utils/Logger");
const CaptainManager = require("../../user/CaptainManager");
const CaptainManager = require("../../user/system/CaptainManager");
const CaptainConstants = require("../../utils/CaptainConstants");
const InjectionExtractor = require("../../injection/InjectionExtractor");
const uuid = require("uuid/v4");
@@ -1 +1 @@
{"version":3,"file":"SystemRouteSelfHostRegistry.js","sourceRoot":"","sources":["../../../src/routes/system/SystemRouteSelfHostRegistry.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"SystemRouteSelfHostRegistry.js","sourceRoot":"","sources":["../../../src/routes/system/SystemRouteSelfHostRegistry.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ const express = require("express");
const BaseApi = require("../../api/BaseApi");
const ApiStatusCodes = require("../../api/ApiStatusCodes");
const Logger = require("../../utils/Logger");
const CaptainManager = require("../../user/CaptainManager");
const CaptainManager = require("../../user/system/CaptainManager");
const Validator = require("validator");
const SystemRouteSelfHostRegistry = require("./SystemRouteSelfHostRegistry");
const CaptainConstants = require("../../utils/CaptainConstants");
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -4,7 +4,7 @@ const uuid = require("uuid/v4");
const bcrypt = require("bcryptjs");
const ApiStatusCodes = require("../api/ApiStatusCodes");
const EnvVar = require("../utils/EnvVars");
const CaptainManager = require("./CaptainManager");
const CaptainManager = require("./system/CaptainManager");
const CaptainConstants = require("../utils/CaptainConstants");
const Logger = require("../utils/Logger");
const DataStoreProvider = require("../datastore/DataStoreProvider");
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
"use strict";
const Logger = require("../utils/Logger");
const CaptainConstants = require("../utils/CaptainConstants");
const CaptainManager = require("./CaptainManager");
const CaptainManager = require("./system/CaptainManager");
const ApiStatusCodes = require("../api/ApiStatusCodes");
const Authenticator = require("./Authenticator");
const requireFromString = require("require-from-string");
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -2,7 +2,7 @@
const fs = require("fs-extra");
const ApiStatusCodes = require("../api/ApiStatusCodes");
const CaptainConstants = require("../utils/CaptainConstants");
const TemplateHelperVersionPrinter = require("./TemplateHelperVersionPrinter");
const TemplateHelperVersionPrinter = require("../utils/TemplateHelperVersionPrinter");
class TemplateHelper {
constructor() {
const templates = [
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"TemplateHelper.js","sourceRoot":"","sources":["../../src/user/TemplateHelper.ts"],"names":[],"mappings":";AACA,+BAA+B;AAC/B,wDAAwD;AAExD,8DAA8D;AAE9D,+EAA+E;AAE/E,MAAM,cAAc;IAGhB;QACI,MAAM,SAAS,GAAgB;YAC3B;gBACI,YAAY,EAAE,MAAM;gBACpB,kBAAkB,EAAE,cAAc;gBAClC,SAAS,EAAE,SAAS;aACvB;YACD;gBACI,YAAY,EAAE,KAAK;gBACnB,kBAAkB,EAAE,aAAa;gBACjC,SAAS,EAAE,SAAS;aACvB;YACD;gBACI,YAAY,EAAE,eAAe;gBAC7B,kBAAkB,EAAE,gBAAgB;gBACpC,SAAS,EAAE,YAAY;aAC1B;YACD;gBACI,YAAY,EAAE,WAAW;gBACzB,kBAAkB,EAAE,cAAc;gBAClC,SAAS,EAAE,YAAY;aAC1B;SACJ,CAAA;QAED,MAAM,eAAe,GAAG,SAAS,GAAG,qBAAqB,CAAA;QAEzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACvC,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,GAAG,EAAE,CAAC,YAAY,CACxC,eAAe,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,EAC3C,MAAM,CACT,CAAA;SACJ;QAED,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAE1B,IAAI,gBAAgB,CAAC,OAAO,EAAE;YAC1B,IAAI,4BAA4B,EAAE,CAAC,gCAAgC,CAC/D,IAAI,CAAC,SAAS,CACjB,CAAA;SACJ;IACL,CAAC;IAED,2BAA2B,CAAC,YAAoB;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC5C,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,YAAY,EAAE;gBACjD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;aAC3B;SACJ;QACD,MAAM,cAAc,CAAC,WAAW,CAC5B,cAAc,CAAC,oBAAoB,EACnC,2BAA2B,GAAG,YAAY,CAC7C,CAAA;IACL,CAAC;IAED,mCAAmC,CAAC,kBAA0B;QAC1D,MAAM,IAAI,GAAG,IAAI,CAAA;QACjB,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACrD,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACxD,IAAI,CAAC,eAAe,EAAE;YAClB,MAAM,cAAc,CAAC,WAAW,CAC5B,cAAc,CAAC,oBAAoB,EACnC,kCAAkC,CACrC,CAAA;SACJ;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,2BAA2B,CAAC,YAAY,CAAC,CAAA;QAElE,MAAM,QAAQ,GACV,WAAW,CAAC,kBAAkB;YAC9B,GAAG;YACH,eAAe;YACf,WAAW,CAAC,SAAS,CAAA;QAEzB,OAAO,OAAO,GAAG,QAAQ,GAAG,IAAI,GAAG,WAAW,CAAC,aAAa,CAAA;IAChE,CAAC;CACJ;AAED,MAAM,sBAAsB,GAAG,IAAI,cAAc,EAAE,CAAA;AAEnD,iBAAS;IACL,GAAG,EAAE;QACD,OAAO,sBAAsB,CAAA;IACjC,CAAC;CACJ,CAAA"}
{"version":3,"file":"TemplateHelper.js","sourceRoot":"","sources":["../../src/user/TemplateHelper.ts"],"names":[],"mappings":";AACA,+BAA+B;AAC/B,wDAAwD;AAExD,8DAA8D;AAE9D,sFAAsF;AAEtF,MAAM,cAAc;IAGhB;QACI,MAAM,SAAS,GAAgB;YAC3B;gBACI,YAAY,EAAE,MAAM;gBACpB,kBAAkB,EAAE,cAAc;gBAClC,SAAS,EAAE,SAAS;aACvB;YACD;gBACI,YAAY,EAAE,KAAK;gBACnB,kBAAkB,EAAE,aAAa;gBACjC,SAAS,EAAE,SAAS;aACvB;YACD;gBACI,YAAY,EAAE,eAAe;gBAC7B,kBAAkB,EAAE,gBAAgB;gBACpC,SAAS,EAAE,YAAY;aAC1B;YACD;gBACI,YAAY,EAAE,WAAW;gBACzB,kBAAkB,EAAE,cAAc;gBAClC,SAAS,EAAE,YAAY;aAC1B;SACJ,CAAA;QAED,MAAM,eAAe,GAAG,SAAS,GAAG,qBAAqB,CAAA;QAEzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACvC,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,GAAG,EAAE,CAAC,YAAY,CACxC,eAAe,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,EAC3C,MAAM,CACT,CAAA;SACJ;QAED,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAE1B,IAAI,gBAAgB,CAAC,OAAO,EAAE;YAC1B,IAAI,4BAA4B,EAAE,CAAC,gCAAgC,CAC/D,IAAI,CAAC,SAAS,CACjB,CAAA;SACJ;IACL,CAAC;IAED,2BAA2B,CAAC,YAAoB;QAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC5C,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,YAAY,EAAE;gBACjD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;aAC3B;SACJ;QACD,MAAM,cAAc,CAAC,WAAW,CAC5B,cAAc,CAAC,oBAAoB,EACnC,2BAA2B,GAAG,YAAY,CAC7C,CAAA;IACL,CAAC;IAED,mCAAmC,CAAC,kBAA0B;QAC1D,MAAM,IAAI,GAAG,IAAI,CAAA;QACjB,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACrD,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACxD,IAAI,CAAC,eAAe,EAAE;YAClB,MAAM,cAAc,CAAC,WAAW,CAC5B,cAAc,CAAC,oBAAoB,EACnC,kCAAkC,CACrC,CAAA;SACJ;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,2BAA2B,CAAC,YAAY,CAAC,CAAA;QAElE,MAAM,QAAQ,GACV,WAAW,CAAC,kBAAkB;YAC9B,GAAG;YACH,eAAe;YACf,WAAW,CAAC,SAAS,CAAA;QAEzB,OAAO,OAAO,GAAG,QAAQ,GAAG,IAAI,GAAG,WAAW,CAAC,aAAa,CAAA;IAChE,CAAC;CACJ;AAED,MAAM,sBAAsB,GAAG,IAAI,cAAc,EAAE,CAAA;AAEnD,iBAAS;IACL,GAAG,EAAE;QACD,OAAO,sBAAsB,CAAA;IACjC,CAAC;CACJ,CAAA"}
@@ -0,0 +1,692 @@
"use strict";
const uuid = require("uuid/v4");
const SshClientImport = require("ssh2");
const request = require("request");
const fs = require("fs-extra");
const CaptainConstants = require("../../utils/CaptainConstants");
const Logger = require("../../utils/Logger");
const LoadBalancerManager = require("./LoadBalancerManager");
const CertbotManager = require("./CertbotManager");
const SelfHostedDockerRegistry = require("./SelfHostedDockerRegistry");
const ApiStatusCodes = require("../../api/ApiStatusCodes");
const DataStoreProvider = require("../../datastore/DataStoreProvider");
const DockerApi = require("../../docker/DockerApi");
const DEBUG_SALT = 'THIS IS NOT A REAL CERTIFICATE';
const SshClient = SshClientImport.Client;
const MAX_FAIL_ALLOWED = 4;
const HEALTH_CHECK_INTERVAL = 20000; // ms
const TIMEOUT_HEALTH_CHECK = 15000; // ms
class CaptainManager {
constructor() {
const dockerApi = DockerApi.get();
this.hasForceSsl = false;
this.dataStore = DataStoreProvider.getDataStore(CaptainConstants.rootNameSpace);
this.dockerApi = dockerApi;
this.certbotManager = new CertbotManager(dockerApi);
this.loadBalancerManager = new LoadBalancerManager(dockerApi, this.certbotManager, this.dataStore);
this.dockerRegistry = new SelfHostedDockerRegistry(dockerApi, this.dataStore, this.certbotManager, this.loadBalancerManager, this);
this.myNodeId = undefined;
this.inited = false;
this.waitUntilRestarted = false;
this.captainSalt = '';
this.consecutiveHealthCheckFailCount = 0;
this.healthCheckUuid = uuid();
}
initialize() {
// If a linked file / directory is deleted on the host, it loses the connection to
// the container and needs an update to be picked up again.
const self = this;
const dataStore = this.dataStore;
const dockerApi = this.dockerApi;
const loadBalancerManager = this.loadBalancerManager;
const certbotManager = this.certbotManager;
let myNodeId;
self.refreshForceSslState()
.then(function () {
return dockerApi.getNodeIdByServiceName(CaptainConstants.captainServiceName, 0);
})
.then(function (nodeId) {
myNodeId = nodeId;
self.myNodeId = myNodeId;
return dockerApi.isNodeManager(myNodeId);
})
.then(function (isManager) {
if (!isManager) {
throw new Error('Captain should only run on a manager node');
}
})
.then(function () {
Logger.d('Emptying generated and temp folders.');
return fs.emptyDir(CaptainConstants.captainRootDirectoryTemp);
})
.then(function () {
return fs.emptyDir(CaptainConstants.captainRootDirectoryGenerated);
})
.then(function () {
Logger.d('Ensuring directories are available on host. Started.');
return fs.ensureDir(CaptainConstants.letsEncryptEtcPath);
})
.then(function () {
return fs.ensureDir(CaptainConstants.letsEncryptLibPath);
})
.then(function () {
return fs.ensureDir(CaptainConstants.captainStaticFilesDir);
})
.then(function () {
return fs.ensureDir(CaptainConstants.perAppNginxConfigPathBase);
})
.then(function () {
return fs.ensureFile(CaptainConstants.baseNginxConfigPath);
})
.then(function () {
return fs.ensureDir(CaptainConstants.registryPathOnHost);
})
.then(function () {
return dockerApi.ensureOverlayNetwork(CaptainConstants.captainNetworkName);
})
.then(function () {
Logger.d('Ensuring directories are available on host. Finished.');
return dockerApi.ensureServiceConnectedToNetwork(CaptainConstants.captainServiceName, CaptainConstants.captainNetworkName);
})
.then(function () {
return loadBalancerManager.init(myNodeId, dataStore);
})
.then(function () {
const valueIfNotExist = CaptainConstants.isDebug
? DEBUG_SALT
: uuid();
return dockerApi.ensureSecret(CaptainConstants.captainSaltSecretKey, valueIfNotExist);
})
.then(function () {
return dockerApi.ensureSecretOnService(CaptainConstants.captainServiceName, CaptainConstants.captainSaltSecretKey);
})
.then(function (secretHadExistedBefore) {
if (!secretHadExistedBefore) {
return new Promise(function () {
Logger.d('I am halting here. I expect to get restarted in a few seconds due to a secret (captain salt) being updated.');
});
}
})
.then(function () {
const secretFileName = '/run/secrets/' + CaptainConstants.captainSaltSecretKey;
if (!fs.existsSync(secretFileName)) {
throw new Error('Secret is attached according to Docker. But file cannot be found. ' +
secretFileName);
}
const secretContent = fs.readFileSync(secretFileName).toString();
if (!secretContent) {
throw new Error('Salt secret content is empty!');
}
self.captainSalt = secretContent;
return true;
})
.then(function () {
return dataStore.setEncryptionSalt(self.getCaptainSalt());
})
.then(function () {
return certbotManager.init(myNodeId);
})
.then(function () {
return dataStore.getRegistriesDataStore().getAllRegistries();
})
.then(function (registries) {
let localRegistry = undefined;
for (let idx = 0; idx < registries.length; idx++) {
const element = registries[idx];
if (element.registryType == IRegistryTypes.LOCAL_REG) {
localRegistry = element;
}
}
if (!!localRegistry) {
Logger.d('Ensuring Docker Registry is running...');
return self.dockerRegistry.ensureDockerRegistryRunningOnThisNode(localRegistry.registryPassword);
}
return Promise.resolve(true);
})
.then(function () {
self.inited = true;
self.performHealthCheck();
Logger.d('**** Captain is initialized and ready to serve you! ****');
})
.catch(function (error) {
Logger.e(error);
setTimeout(function () {
process.exit(0);
}, 5000);
});
}
performHealthCheck() {
const self = this;
const captainPublicDomain = CaptainConstants.captainSubDomain +
'.' +
self.dataStore.getRootDomain();
function scheduleNextHealthCheck() {
self.healthCheckUuid = uuid();
setTimeout(function () {
self.performHealthCheck();
}, HEALTH_CHECK_INTERVAL);
}
// For debug build, we'll turn off health check
if (CaptainConstants.isDebug || !self.dataStore.hasCustomDomain()) {
scheduleNextHealthCheck();
return;
}
function checkCaptainHealth(callback) {
let callbackCalled = false;
setTimeout(function () {
if (callbackCalled) {
return;
}
callbackCalled = true;
callback(false);
}, TIMEOUT_HEALTH_CHECK);
const url = 'http://' +
captainPublicDomain +
CaptainConstants.healthCheckEndPoint;
request(url, function (error, response, body) {
if (callbackCalled) {
return;
}
callbackCalled = true;
if (error || !body || body !== self.getHealthCheckUuid()) {
callback(false);
}
else {
callback(true);
}
});
}
function checkNginxHealth(callback) {
let callbackCalled = false;
setTimeout(function () {
if (callbackCalled) {
return;
}
callbackCalled = true;
callback(false);
}, TIMEOUT_HEALTH_CHECK);
self.verifyCaptainOwnsDomainOrThrow(captainPublicDomain, '-healthcheck')
.then(function () {
if (callbackCalled) {
return;
}
callbackCalled = true;
callback(true);
})
.catch(function () {
if (callbackCalled) {
return;
}
callbackCalled = true;
callback(false);
});
}
const checksPerformed = {};
function scheduleIfNecessary() {
if (!checksPerformed.captainHealth ||
!checksPerformed.nginxHealth) {
return;
}
let hasFailedCheck = false;
if (!checksPerformed.captainHealth.value) {
Logger.w('Captain health check failed: #' +
self.consecutiveHealthCheckFailCount +
' at ' +
captainPublicDomain);
hasFailedCheck = true;
}
if (!checksPerformed.nginxHealth.value) {
Logger.w('NGINX health check failed: #' +
self.consecutiveHealthCheckFailCount);
hasFailedCheck = true;
}
if (hasFailedCheck) {
self.consecutiveHealthCheckFailCount =
self.consecutiveHealthCheckFailCount + 1;
}
else {
self.consecutiveHealthCheckFailCount = 0;
}
scheduleNextHealthCheck();
if (self.consecutiveHealthCheckFailCount > MAX_FAIL_ALLOWED) {
process.exit(1);
}
}
checkCaptainHealth(function (success) {
checksPerformed.captainHealth = {
value: success,
};
scheduleIfNecessary();
});
checkNginxHealth(function (success) {
checksPerformed.nginxHealth = {
value: success,
};
scheduleIfNecessary();
});
}
getHealthCheckUuid() {
return this.healthCheckUuid;
}
isInitialized() {
return this.inited && !this.waitUntilRestarted;
}
getCaptainImageTags() {
const url = 'https://hub.docker.com/v2/repositories/' +
CaptainConstants.configs.publishedNameOnDockerHub +
'/tags';
return new Promise(function (resolve, reject) {
request(url, function (error, response, body) {
if (CaptainConstants.isDebug) {
resolve(['v0.0.1']);
return;
}
if (error) {
reject(error);
}
else if (!body || !JSON.parse(body).results) {
reject(new Error('Received empty body or no result for version list on docker hub.'));
}
else {
const results = JSON.parse(body).results;
const tags = [];
for (let idx = 0; idx < results.length; idx++) {
tags.push(results[idx].name);
}
resolve(tags);
}
});
});
}
updateCaptain(versionTag) {
const self = this;
return Promise.resolve().then(function () {
return self.dockerApi.updateService(CaptainConstants.captainServiceName, CaptainConstants.configs.publishedNameOnDockerHub + ':' + versionTag, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
});
}
getMyNodeId() {
if (!this.myNodeId) {
const msg = 'myNodeId is not set yet!!';
Logger.e(msg);
throw new Error(msg);
}
return this.myNodeId;
}
getCaptainSalt() {
if (!this.captainSalt) {
const msg = 'Captain Salt is not set yet!!';
Logger.e(msg);
throw new Error(msg);
}
return this.captainSalt;
}
updateNetDataInfo(netDataInfo) {
const self = this;
const dockerApi = this.dockerApi;
return Promise.resolve()
.then(function () {
return dockerApi.ensureContainerStoppedAndRemoved(CaptainConstants.netDataContainerName, CaptainConstants.captainNetworkName);
})
.then(function () {
if (netDataInfo.isEnabled) {
const vols = [
{
hostPath: '/proc',
containerPath: '/host/proc',
mode: 'ro',
},
{
hostPath: '/sys',
containerPath: '/host/sys',
mode: 'ro',
},
{
hostPath: '/var/run/docker.sock',
containerPath: '/var/run/docker.sock',
},
];
const envVars = [];
if (netDataInfo.data.smtp) {
envVars.push({
key: 'SSMTP_TO',
value: netDataInfo.data.smtp.to,
});
envVars.push({
key: 'SSMTP_HOSTNAME',
value: netDataInfo.data.smtp.hostname,
});
envVars.push({
key: 'SSMTP_SERVER',
value: netDataInfo.data.smtp.server,
});
envVars.push({
key: 'SSMTP_PORT',
value: netDataInfo.data.smtp.port,
});
envVars.push({
key: 'SSMTP_TLS',
value: netDataInfo.data.smtp.allowNonTls
? 'NO'
: 'YES',
});
envVars.push({
key: 'SSMTP_USER',
value: netDataInfo.data.smtp.username,
});
envVars.push({
key: 'SSMTP_PASS',
value: netDataInfo.data.smtp.password,
});
}
if (netDataInfo.data.slack) {
envVars.push({
key: 'SLACK_WEBHOOK_URL',
value: netDataInfo.data.slack.hook,
});
envVars.push({
key: 'SLACK_CHANNEL',
value: netDataInfo.data.slack.channel,
});
}
if (netDataInfo.data.telegram) {
envVars.push({
key: 'TELEGRAM_BOT_TOKEN',
value: netDataInfo.data.telegram.botToken,
});
envVars.push({
key: 'TELEGRAM_CHAT_ID',
value: netDataInfo.data.telegram.chatId,
});
}
if (netDataInfo.data.pushBullet) {
envVars.push({
key: 'PUSHBULLET_ACCESS_TOKEN',
value: netDataInfo.data.pushBullet.apiToken,
});
envVars.push({
key: 'PUSHBULLET_DEFAULT_EMAIL',
value: netDataInfo.data.pushBullet.fallbackEmail,
});
}
return dockerApi.createStickyContainer(CaptainConstants.netDataContainerName, CaptainConstants.netDataImageName, vols, CaptainConstants.captainNetworkName, envVars, ['SYS_PTRACE']);
}
// Just removing the old container. No need to create a new one.
return true;
})
.then(function () {
return self.dataStore.setNetDataInfo(netDataInfo);
});
}
getNodesInfo() {
const dockerApi = this.dockerApi;
return Promise.resolve()
.then(function () {
return dockerApi.getNodesInfo();
})
.then(function (data) {
if (!data || !data.length) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'No cluster node was found!');
}
return data;
});
}
joinDockerNode(captainIpAddress, isManager, remoteNodeIpAddress, remoteUserName, privateKey) {
const dockerApi = this.dockerApi;
return Promise.resolve()
.then(function () {
return dockerApi.getJoinToken(isManager);
})
.then(function (token) {
return new Promise(function (resolve, reject) {
const conn = new SshClient();
conn.on('error', function (err) {
Logger.e(err);
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'SSH Connection error!!'));
})
.on('ready', function () {
Logger.d('SSH Client :: ready');
conn.exec(dockerApi.createJoinCommand(captainIpAddress, token), function (err, stream) {
if (err) {
Logger.e(err);
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'SSH Running command failed!!'));
return;
}
let hasExisted = false;
stream
.on('close', function (code, signal) {
Logger.d('Stream :: close :: code: ' +
code +
', signal: ' +
signal);
conn.end();
if (hasExisted) {
return;
}
hasExisted = true;
resolve();
})
.on('data', function (data) {
Logger.d('STDOUT: ' + data);
})
.stderr.on('data', function (data) {
Logger.e('STDERR: ' + data);
if (hasExisted) {
return;
}
hasExisted = true;
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'Error during setup: ' +
data));
});
});
})
.connect({
host: remoteNodeIpAddress,
port: 22,
username: remoteUserName,
privateKey: privateKey,
});
});
});
}
getLoadBalanceManager() {
return this.loadBalancerManager;
}
reloadLoadBalancer(datastore) {
const self = this;
return self.loadBalancerManager
.rePopulateNginxConfigFile(datastore)
.then(function () {
Logger.d('sendReloadSignal...');
return self.loadBalancerManager.sendReloadSignal();
});
}
getDockerRegistry() {
return this.dockerRegistry;
}
enableSsl(emailAddress) {
const self = this;
return Promise.resolve()
.then(function () {
return self.certbotManager.ensureRegistered(emailAddress);
})
.then(function () {
return self.certbotManager.enableSsl(CaptainConstants.captainSubDomain +
'.' +
self.dataStore.getRootDomain());
})
.then(function () {
return self.dataStore.setUserEmailAddress(emailAddress);
})
.then(function () {
return self.dataStore.setHasRootSsl(true);
})
.then(function () {
return self.loadBalancerManager.rePopulateNginxConfigFile(self.dataStore);
})
.then(function () {
return self.loadBalancerManager.sendReloadSignal();
});
}
forceSsl(isEnabled) {
const self = this;
return Promise.resolve()
.then(function () {
return self.dataStore.getHasRootSsl();
})
.then(function (hasRootSsl) {
if (!hasRootSsl) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'You first need to enable SSL on the root domain before forcing it.');
}
return self.dataStore.setForceSsl(isEnabled);
})
.then(function () {
return self.refreshForceSslState();
});
}
refreshForceSslState() {
const self = this;
return Promise.resolve()
.then(function () {
return self.dataStore.getForceSsl();
})
.then(function (hasForceSsl) {
self.hasForceSsl = hasForceSsl;
});
}
getForceSslValue() {
return !!this.hasForceSsl;
}
/**
* Returns a promise successfully if verification is succeeded. If it fails, it throws an exception.
*
* @param domainName the domain to verify, app.mycaptainroot.com or www.myawesomeapp.com
* @param identifierSuffix an optional suffix to be added to the identifier file name to avoid name conflict
*
* @returns {Promise.<boolean>}
*/
verifyCaptainOwnsDomainOrThrow(domainName, identifierSuffix) {
const self = this;
const randomUuid = uuid();
const captainConfirmationPath = CaptainConstants.captainConfirmationPath +
(identifierSuffix ? identifierSuffix : '');
return Promise.resolve()
.then(function () {
return self.certbotManager.domainValidOrThrow(domainName);
})
.then(function () {
return fs.outputFile(CaptainConstants.captainStaticFilesDir +
CaptainConstants.nginxDomainSpecificHtmlDir +
'/' +
domainName +
captainConfirmationPath, randomUuid);
})
.then(function () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve();
}, 1000);
});
})
.then(function () {
return new Promise(function (resolve, reject) {
const url = 'http://' +
domainName +
':' +
CaptainConstants.nginxPortNumber +
captainConfirmationPath;
request(url, function (error, response, body) {
if (error || !body || body !== randomUuid) {
Logger.e('Verification Failed for ' + domainName);
Logger.e('Error ' + error);
Logger.e('body ' + body);
Logger.e('randomUuid ' + randomUuid);
reject(ApiStatusCodes.createError(ApiStatusCodes.VERIFICATION_FAILED, 'Verification Failed.'));
return;
}
resolve();
});
});
});
}
getNginxConfig() {
const self = this;
return Promise.resolve().then(function () {
return self.dataStore.getNginxConfig();
});
}
setNginxConfig(baseConfig, captainConfig) {
const self = this;
return Promise.resolve()
.then(function () {
return self.dataStore.setNginxConfig(baseConfig, captainConfig);
})
.then(function () {
self.resetSelf();
});
}
requestCertificateForDomain(domainName) {
return this.certbotManager.enableSsl(domainName);
}
verifyDomainResolvesToDefaultServerOnHost(domainName) {
const self = this;
return new Promise(function (resolve, reject) {
const url = 'http://' +
domainName +
CaptainConstants.captainConfirmationPath;
Logger.d('Sending request to ' + url);
request(url, function (error, response, body) {
if (error ||
!body ||
body !==
self.loadBalancerManager.getCaptainPublicRandomKey()) {
reject(ApiStatusCodes.createError(ApiStatusCodes.VERIFICATION_FAILED, 'Verification Failed.'));
return;
}
resolve();
});
});
}
changeCaptainRootDomain(requestedCustomDomain) {
const self = this;
// Some DNS servers do not allow wild cards. Therefore this line may fail.
// We still allow users to specify the domains in their DNS settings individually
// SubDomains that need to be added are "captain." "registry." "app-name."
const url = (CaptainConstants.configs.preCheckForWildCard
? uuid()
: CaptainConstants.captainSubDomain) +
'.' +
requestedCustomDomain +
':' +
CaptainConstants.nginxPortNumber;
return self
.verifyDomainResolvesToDefaultServerOnHost(url)
.then(function () {
return self.dataStore.getHasRootSsl();
})
.then(function (hasRootSsl) {
if (hasRootSsl &&
self.dataStore.getRootDomain() !== requestedCustomDomain) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'SSL is enabled for root. Too late to change your mind!');
}
return self.dataStore.setCustomDomain(requestedCustomDomain);
})
.then(function () {
return self.reloadLoadBalancer(self.dataStore);
});
}
resetSelf() {
const self = this;
Logger.d('Captain is resetting itself!');
return new Promise(function (resolve, reject) {
setTimeout(function () {
const promiseToIgnore = self.dockerApi.updateService(CaptainConstants.captainServiceName, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
}, 2000);
});
}
static get() {
return captainManagerInstance;
}
}
const captainManagerInstance = new CaptainManager();
module.exports = CaptainManager;
//# sourceMappingURL=CaptainManager.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,288 @@
"use strict";
const CaptainConstants = require("../../utils/CaptainConstants");
const Logger = require("../../utils/Logger");
const fs = require("fs-extra");
const ApiStatusCodes = require("../../api/ApiStatusCodes");
const CAPTAIN_WEBROOT_PATH_CERTBOT = '/captain-webroot';
const shouldUseStaging = false; // CaptainConstants.isDebug;
class CertbotManager {
constructor(dockerApi) {
this.dockerApi = dockerApi;
this.dockerApi = dockerApi;
}
domainValidOrThrow(domainName) {
if (!domainName) {
throw new Error('Domain Name is empty');
}
const RegExpression = /^[a-z0-9\.\-]*$/;
if (!RegExpression.test(domainName)) {
throw new Error('Bad Domain Name!');
}
}
getCertRelativePathForDomain(domainName) {
const self = this;
self.domainValidOrThrow(domainName);
return '/live/' + domainName + '/fullchain.pem';
}
getKeyRelativePathForDomain(domainName) {
const self = this;
self.domainValidOrThrow(domainName);
return '/live/' + domainName + '/privkey.pem';
}
enableSsl(domainName) {
const dockerApi = this.dockerApi;
const self = this;
Logger.d('Enabling SSL for ' + domainName);
self.domainValidOrThrow(domainName);
return Promise.resolve()
.then(function () {
const webrootInCaptainContainer = CaptainConstants.captainStaticFilesDir +
CaptainConstants.nginxDomainSpecificHtmlDir +
'/' +
domainName;
return fs.ensureDir(webrootInCaptainContainer);
})
.then(function () {
const cmd = [
'certbot',
'certonly',
'--webroot',
'-w',
CAPTAIN_WEBROOT_PATH_CERTBOT + '/' + domainName,
'-d',
domainName,
'--non-interactive',
];
if (shouldUseStaging) {
cmd.push('--staging');
}
return self.runCommand(cmd).then(function (output) {
Logger.d(output);
if (output.indexOf('Congratulations! Your certificate and chain have been saved') >= 0) {
return true;
}
if (output.indexOf('Certificate not yet due for renewal; no action taken') >= 0) {
return true;
}
throw ApiStatusCodes.createError(ApiStatusCodes.VERIFICATION_FAILED, 'Unexpected output when enabling SSL for' +
domainName +
' with ACME Certbot \n' +
output);
});
});
}
ensureRegistered(emailAddress) {
const dockerApi = this.dockerApi;
const self = this;
return Promise.resolve()
.then(function () {
const rootPathDir = CaptainConstants.letsEncryptEtcPath +
'/accounts/acme-' +
(shouldUseStaging ? 'staging' : 'v01') +
'.api.letsencrypt.org/directory';
if (!fs.existsSync(rootPathDir)) {
Logger.d('Fresh install of Certbot. There is no registration directory');
return undefined;
}
const files = fs.readdirSync(rootPathDir);
if (files.length === 0) {
Logger.d('Fresh install of Certbot. There is nothing in the registration directory');
return undefined;
}
if (files.length !== 1) {
throw new Error('I do not know know what to do when there are multiple directories in ' +
rootPathDir);
}
const regFilePath = rootPathDir + '/' + files[0] + '/regr.json';
if (!fs.existsSync(regFilePath)) {
throw new Error('ACME Reg directory exists, but there is no file! ' +
regFilePath);
}
return fs.readJson(regFilePath);
})
.then(function (regrContent) {
if (!regrContent) {
const cmd = [
'certbot',
'register',
'--email',
emailAddress,
'--agree-tos',
'--no-eff-email',
'--non-interactive',
];
if (shouldUseStaging) {
cmd.push('--staging');
}
return self.runCommand(cmd).then(function (registerOutput) {
if (registerOutput.indexOf('Your account credentials have been saved in your Certbot') >= 0) {
return true;
}
throw new Error('Unexpected output when registering with ACME Certbot \n' +
registerOutput);
});
}
else {
/*
/etc/letsencrypt/accounts/acme-v01.api.letsencrypt.org/directory/864339b5816d33d67743 # cat regr.json
{
"body":{
"contact":[
"mailto:testemail@gmail.com"
],
"agreement":"https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf",
"key":{
"e":"AQAB",
"kty":"RSA",
"n":"1l-5ihAl0BFSiS3Pl3LjQ"
}
},
"uri":"https://acme-v01.api.letsencrypt.org/acme/reg/0421",
"new_authzr_uri":"https://acme-v01.api.letsencrypt.org/acme/new-authz",
"terms_of_service":"https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
}
*/
let contact = undefined;
if (regrContent &&
regrContent.body &&
regrContent.body.contact &&
Array.isArray(regrContent.body.contact)) {
contact = regrContent.body.contact;
for (let idx = 0; idx < contact.length; idx++) {
if (contact[idx] === 'mailto:' + emailAddress) {
return true;
}
}
}
throw new Error('Previously registered with a different address: ' +
contact
? JSON.stringify(contact)
: 'NULL');
}
});
}
runCommand(cmd) {
const dockerApi = this.dockerApi;
const self = this;
return Promise.resolve().then(function () {
return dockerApi.executeCommand(CaptainConstants.certbotServiceName, cmd);
});
}
renewAllCerts() {
const self = this;
/*
From Certbot docs:
This command attempts to renew all previously-obtained certificates that expire in less than 30 days.
The same plugin and options that were used at the time the certificate was originally issued will be
used for the renewal attempt, unless you specify other plugins or options. Unlike certonly, renew
acts on multiple certificates and always takes into account whether each one is near expiry. Because
of this, renew is suitable (and designed) for automated use, to allow your system to automatically
renew each certificate when appropriate. Since renew only renews certificates that are near expiry
it can be run as frequently as you want - since it will usually take no action.
*/
// before doing renewal, let's schedule the next one in 20.3 hours!
// this random schedule helps to avoid retrying at the same time of
// the day in case if that's our super high traffic time
setTimeout(function () {
self.renewAllCerts();
}, 1000 * 3600 * 20.3);
const cmd = ['certbot', 'renew'];
if (shouldUseStaging) {
cmd.push('--staging');
}
return self.runCommand(cmd).then(function (output) {
// Ignore output :)
});
}
init(myNodeId) {
const dockerApi = this.dockerApi;
const self = this;
const domainSpecificRootDirectoryInHost = CaptainConstants.captainStaticFilesDir +
CaptainConstants.nginxDomainSpecificHtmlDir;
function createCertbotServiceOnNode(nodeId) {
return dockerApi
.createServiceOnNodeId(CaptainConstants.certbotImageName, CaptainConstants.certbotServiceName, undefined, nodeId, undefined, undefined, undefined)
.then(function () {
const waitTimeInMillis = 5000;
Logger.d('Waiting for ' +
waitTimeInMillis / 1000 +
' seconds for Certbot to start up');
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(true);
}, waitTimeInMillis);
});
});
}
return Promise.resolve()
.then(function () {
return fs.ensureDir(CaptainConstants.letsEncryptEtcPath);
})
.then(function () {
return fs.ensureDir(CaptainConstants.letsEncryptLibPath);
})
.then(function () {
return fs.ensureDir(domainSpecificRootDirectoryInHost);
})
.then(function () {
return dockerApi.isServiceRunningByName(CaptainConstants.certbotServiceName);
})
.then(function (isRunning) {
if (isRunning) {
Logger.d('Captain Certbot is already running.. ');
return dockerApi.getNodeIdByServiceName(CaptainConstants.certbotServiceName, 0);
}
else {
Logger.d('No Captain Certbot service is running. Creating one...');
return createCertbotServiceOnNode(myNodeId).then(function () {
return myNodeId;
});
}
})
.then(function (nodeId) {
if (nodeId !== myNodeId) {
Logger.d('Captain Certbot is running on a different node. Removing...');
return dockerApi
.removeServiceByName(CaptainConstants.certbotServiceName)
.then(function () {
return createCertbotServiceOnNode(myNodeId).then(function () {
return true;
});
});
}
else {
return true;
}
})
.then(function () {
Logger.d('Updating Certbot service...');
return dockerApi.updateService(CaptainConstants.certbotServiceName, undefined, [
{
hostPath: CaptainConstants.letsEncryptEtcPath,
containerPath: '/etc/letsencrypt',
},
{
hostPath: CaptainConstants.letsEncryptLibPath,
containerPath: '/var/lib/letsencrypt',
},
{
hostPath: domainSpecificRootDirectoryInHost,
containerPath: CAPTAIN_WEBROOT_PATH_CERTBOT,
},
],
// No need to certbot to be connected to the network
undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
})
.then(function () {
// schedule the first attempt to renew certs in 1 minute
setTimeout(function () {
self.renewAllCerts();
}, 1000 * 60);
});
}
}
module.exports = CertbotManager;
//# sourceMappingURL=CertbotManager.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,393 @@
"use strict";
const ejs = require("ejs");
const CaptainConstants = require("../../utils/CaptainConstants");
const Logger = require("../../utils/Logger");
const fs = require("fs-extra");
const uuid = require("uuid/v4");
const request = require("request");
const ApiStatusCodes = require("../../api/ApiStatusCodes");
const defaultPageTemplate = fs
.readFileSync(__dirname + '/../../template/default-page.ejs')
.toString();
class LoadBalancerManager {
constructor(dockerApi, certbotManager, dataStore) {
this.dockerApi = dockerApi;
this.certbotManager = certbotManager;
this.dataStore = dataStore;
this.reloadInProcess = false;
this.requestedReloadPromises = [];
this.captainPublicRandomKey = uuid();
}
/**
* Reloads the configuation for NGINX.
* NOTE that this can return synchronously with UNDEFINED if there is already a process in the background.
* @param dataStoreToQueue
* @returns {Promise.<>}
*/
rePopulateNginxConfigFile(dataStoreToQueue) {
const self = this;
return new Promise(function (res, rej) {
self.requestedReloadPromises.push({
dataStore: dataStoreToQueue,
resolve: res,
reject: rej,
});
self.consumeQueueIfAnyInNginxReloadQueue();
});
}
consumeQueueIfAnyInNginxReloadQueue() {
const self = this;
const q = self.requestedReloadPromises.pop();
if (!q) {
return;
}
if (self.reloadInProcess) {
Logger.d('NGINX Reload already in process, Bouncing off...');
return;
}
Logger.d('Locking NGINX configuration reloading...');
self.reloadInProcess = true;
const dataStore = q.dataStore;
// This will resolve to something like: /captain/nginx/conf.d/captain
const configFilePathBase = CaptainConstants.perAppNginxConfigPathBase +
'/' +
dataStore.getNameSpace();
const FUTURE = configFilePathBase + '.fut';
const BACKUP = configFilePathBase + '.bak';
const CONFIG = configFilePathBase + '.conf';
let nginxConfigContent = '';
return Promise.resolve()
.then(function () {
return fs.remove(FUTURE);
})
.then(function () {
return dataStore.getServerList();
})
.then(function (servers) {
const promises = [];
if (servers && !!servers.length) {
for (let i = 0; i < servers.length; i++) {
const s = servers[i];
if (s.hasSsl) {
s.crtPath = self.getSslCertPath(s.publicDomain);
s.keyPath = self.getSslKeyPath(s.publicDomain);
}
s.staticWebRoot =
CaptainConstants.nginxStaticRootDir +
CaptainConstants.nginxDomainSpecificHtmlDir +
'/' +
s.publicDomain;
promises.push(Promise.resolve()
.then(function () {
return ejs.render(s.nginxConfigTemplate, {
s: s,
});
})
.then(function (rendered) {
nginxConfigContent += rendered;
}));
}
}
return Promise.all(promises);
})
.then(function () {
return fs.outputFile(FUTURE, nginxConfigContent);
})
.then(function () {
return fs.remove(BACKUP);
})
.then(function () {
return fs.ensureFile(CONFIG);
})
.then(function () {
return fs.renameSync(CONFIG, BACKUP); // sync method. It's really fast.
})
.then(function () {
return fs.renameSync(FUTURE, CONFIG); // sync method. It's really fast.
})
.then(function () {
return self.createRootConfFile(dataStore);
})
.then(function () {
Logger.d('SUCCESS: UNLocking NGINX configuration reloading...');
self.reloadInProcess = false;
q.resolve();
self.consumeQueueIfAnyInNginxReloadQueue();
})
.catch(function (error) {
Logger.e(error);
Logger.d('Error: UNLocking NGINX configuration reloading...');
self.reloadInProcess = false;
q.reject(error);
self.consumeQueueIfAnyInNginxReloadQueue();
});
}
sendReloadSignal() {
return this.dockerApi.sendSingleContainerKillHUP(CaptainConstants.nginxServiceName);
}
getCaptainPublicRandomKey() {
return this.captainPublicRandomKey;
}
getSslCertPath(domainName) {
const self = this;
return (CaptainConstants.letsEncryptEtcPathOnNginx +
self.certbotManager.getCertRelativePathForDomain(domainName));
}
getSslKeyPath(domainName) {
const self = this;
return (CaptainConstants.letsEncryptEtcPathOnNginx +
self.certbotManager.getKeyRelativePathForDomain(domainName));
}
getInfo() {
return new Promise(function (resolve, reject) {
const url = 'http://' + CaptainConstants.nginxServiceName + '/nginx_status';
request(url, function (error, response, body) {
if (error || !body) {
Logger.e('Error ' + error);
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'Request to nginx Failed.'));
return;
}
try {
const data = new LoadBalancerInfo();
const lines = body.split('\n');
data.activeConnections = Number(lines[0].split(' ')[2].trim());
data.accepted = Number(lines[2].split(' ')[1].trim());
data.handled = Number(lines[2].split(' ')[2].trim());
data.total = Number(lines[2].split(' ')[3].trim());
data.reading = Number(lines[3].split(' ')[1].trim());
data.writing = Number(lines[3].split(' ')[3].trim());
data.waiting = Number(lines[3].split(' ')[5].trim());
resolve(data);
}
catch (error) {
Logger.e('Cannot parse ' + body);
reject(ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'Parser Failed. See internal logs...'));
}
});
});
}
createRootConfFile(dataStore) {
const self = this;
const captainDomain = CaptainConstants.captainSubDomain + '.' + dataStore.getRootDomain();
const registryDomain = CaptainConstants.registrySubDomain + '.' + dataStore.getRootDomain();
let hasRootSsl = false;
const FUTURE = CaptainConstants.rootNginxConfigPath + '.fut';
const BACKUP = CaptainConstants.rootNginxConfigPath + '.bak';
const CONFIG = CaptainConstants.rootNginxConfigPath + '.conf';
let rootNginxTemplate = undefined;
return Promise.resolve()
.then(function () {
return dataStore.getNginxConfig();
})
.then(function (nginxConfig) {
rootNginxTemplate =
nginxConfig.captainConfig.customValue ||
nginxConfig.captainConfig.byDefault;
return dataStore.getHasRootSsl();
})
.then(function (hasSsl) {
hasRootSsl = hasSsl;
return dataStore.getHasRegistrySsl();
})
.then(function (hasRegistrySsl) {
return ejs.render(rootNginxTemplate, {
captain: {
crtPath: self.getSslCertPath(captainDomain),
keyPath: self.getSslKeyPath(captainDomain),
hasRootSsl: hasRootSsl,
serviceName: CaptainConstants.captainServiceName,
domain: captainDomain,
serviceExposedPort: CaptainConstants.captainServiceExposedPort,
defaultHtmlDir: CaptainConstants.nginxStaticRootDir +
CaptainConstants.nginxDefaultHtmlDir,
staticWebRoot: CaptainConstants.nginxStaticRootDir +
CaptainConstants.nginxDomainSpecificHtmlDir +
'/' +
captainDomain,
},
registry: {
crtPath: self.getSslCertPath(registryDomain),
keyPath: self.getSslKeyPath(registryDomain),
hasRootSsl: hasRegistrySsl,
domain: registryDomain,
staticWebRoot: CaptainConstants.nginxStaticRootDir +
CaptainConstants.nginxDomainSpecificHtmlDir +
'/' +
registryDomain,
},
});
})
.then(function (rootNginxConfContent) {
return fs.outputFile(FUTURE, rootNginxConfContent);
})
.then(function () {
return fs.remove(BACKUP);
})
.then(function () {
return fs.ensureFile(CONFIG);
})
.then(function () {
return fs.renameSync(CONFIG, BACKUP); // sync method. It's really fast.
})
.then(function () {
return fs.renameSync(FUTURE, CONFIG); // sync method. It's really fast.
});
}
ensureBaseNginxConf() {
const self = this;
return Promise.resolve()
.then(function () {
return self.dataStore.getNginxConfig();
})
.then(function (captainConfig) {
const baseConfigTemplate = captainConfig.baseConfig.customValue ||
captainConfig.baseConfig.byDefault;
return ejs.render(baseConfigTemplate, {});
})
.then(function (baseNginxConfFileContent) {
return fs.outputFile(CaptainConstants.baseNginxConfigPath, baseNginxConfFileContent);
});
}
init(myNodeId, dataStore) {
const dockerApi = this.dockerApi;
const self = this;
function createNginxServiceOnNode(nodeId) {
Logger.d('No Captain Nginx service is running. Creating one on captain node...');
return dockerApi
.createServiceOnNodeId(CaptainConstants.nginxImageName, CaptainConstants.nginxServiceName, [
{
protocol: 'tcp',
publishMode: 'host',
containerPort: 80,
hostPort: CaptainConstants.nginxPortNumber,
},
{
protocol: 'tcp',
publishMode: 'host',
containerPort: 443,
hostPort: 443,
},
], nodeId, undefined, undefined, {
Reservation: {
MemoryBytes: 30 * 1024 * 1024,
},
})
.then(function () {
const waitTimeInMillis = 5000;
Logger.d('Waiting for ' +
waitTimeInMillis / 1000 +
' seconds for nginx to start up');
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(true);
}, waitTimeInMillis);
});
});
}
return fs
.outputFile(CaptainConstants.captainStaticFilesDir +
CaptainConstants.nginxDefaultHtmlDir +
CaptainConstants.captainConfirmationPath, self.getCaptainPublicRandomKey())
.then(function () {
return ejs.render(defaultPageTemplate, {
message: 'Nothing here yet :/',
});
})
.then(function (staticPageContent) {
return fs.outputFile(CaptainConstants.captainStaticFilesDir +
CaptainConstants.nginxDefaultHtmlDir +
'/index.html', staticPageContent);
})
.then(function () {
return ejs.render(defaultPageTemplate, {
message: 'An Error Occurred :/',
});
})
.then(function (errorPageContent) {
return fs.outputFile(CaptainConstants.captainStaticFilesDir +
CaptainConstants.nginxDefaultHtmlDir +
'/error.html', errorPageContent);
})
.then(function () {
Logger.d('Setting up NGINX conf file...');
return self.ensureBaseNginxConf();
})
.then(function () {
return self.rePopulateNginxConfigFile(dataStore);
})
.then(function () {
return fs.ensureDir(CaptainConstants.letsEncryptEtcPath);
})
.then(function () {
return fs.ensureDir(CaptainConstants.nginxSharedPathOnHost);
})
.then(function () {
return dockerApi.isServiceRunningByName(CaptainConstants.nginxServiceName);
})
.then(function (isRunning) {
if (isRunning) {
Logger.d('Captain Nginx is already running.. ');
return dockerApi.getNodeIdByServiceName(CaptainConstants.nginxServiceName, 0);
}
else {
return createNginxServiceOnNode(myNodeId).then(function () {
return myNodeId;
});
}
})
.then(function (nodeId) {
if (nodeId !== myNodeId) {
Logger.d('Captain Nginx is running on a different node. Removing...');
return dockerApi
.removeServiceByName(CaptainConstants.nginxServiceName)
.then(function () {
return createNginxServiceOnNode(myNodeId).then(function () {
return true;
});
});
}
else {
return true;
}
})
.then(function () {
Logger.d('Updating NGINX service...');
return dockerApi.updateService(CaptainConstants.nginxServiceName, undefined, [
{
containerPath: CaptainConstants.nginxStaticRootDir,
hostPath: CaptainConstants.captainStaticFilesDir,
},
{
containerPath: '/etc/nginx/nginx.conf',
hostPath: CaptainConstants.baseNginxConfigPath,
},
{
containerPath: '/etc/nginx/conf.d',
hostPath: CaptainConstants.perAppNginxConfigPathBase,
},
{
containerPath: CaptainConstants.letsEncryptEtcPathOnNginx,
hostPath: CaptainConstants.letsEncryptEtcPath,
},
{
containerPath: CaptainConstants.nginxSharedPathOnNginx,
hostPath: CaptainConstants.nginxSharedPathOnHost,
},
], [CaptainConstants.captainNetworkName], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
})
.then(function () {
const waitTimeInMillis = 5000;
Logger.d('Waiting for ' +
waitTimeInMillis / 1000 +
' seconds for nginx reload to take into effect');
return new Promise(function (resolve, reject) {
setTimeout(function () {
Logger.d('NGINX is fully set up and working...');
resolve(true);
}, waitTimeInMillis);
});
});
}
}
module.exports = LoadBalancerManager;
//# sourceMappingURL=LoadBalancerManager.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,156 @@
"use strict";
const CaptainConstants = require("../../utils/CaptainConstants");
const Logger = require("../../utils/Logger");
const fs = require("fs-extra");
const ApiStatusCodes = require("../../api/ApiStatusCodes");
const bcrypt = require("bcryptjs");
class SelfHostedDockerRegistry {
constructor(dockerApi, dataStore, certbotManager, loadBalancerManager, captainManager) {
this.dockerApi = dockerApi;
this.dataStore = dataStore;
this.certbotManager = certbotManager;
this.loadBalancerManager = loadBalancerManager;
this.captainManager = captainManager;
//
}
enableRegistrySsl() {
const self = this;
return Promise.resolve()
.then(function () {
return self.dataStore.getHasRootSsl();
})
.then(function (rootHasSsl) {
if (!rootHasSsl) {
throw ApiStatusCodes.createError(ApiStatusCodes.ILLEGAL_OPERATION, 'Root must have SSL before enabling ssl for docker registry.');
}
return self.certbotManager.enableSsl(CaptainConstants.registrySubDomain +
'.' +
self.dataStore.getRootDomain());
})
.then(function () {
return self.dataStore.setHasRegistrySsl(true);
})
.then(function () {
return self.loadBalancerManager.rePopulateNginxConfigFile(self.dataStore);
})
.then(function () {
return self.loadBalancerManager.sendReloadSignal();
});
}
getLocalRegistryDomainAndPort() {
const self = this;
return (CaptainConstants.registrySubDomain +
'.' +
self.dataStore.getRootDomain() +
':' +
CaptainConstants.configs.registrySubDomainPort);
}
ensureServiceRemoved() {
const dockerApi = this.dockerApi;
return Promise.resolve() //
.then(function () {
return dockerApi.isServiceRunningByName(CaptainConstants.registryServiceName);
})
.then(function (isRunning) {
if (!isRunning)
return;
return dockerApi.removeServiceByName(CaptainConstants.registryServiceName);
});
}
ensureDockerRegistryRunningOnThisNode(password) {
const dockerApi = this.dockerApi;
const dataStore = this.dataStore;
const myNodeId = this.captainManager.getMyNodeId();
function createRegistryServiceOnNode() {
return dockerApi.createServiceOnNodeId(CaptainConstants.registryImageName, CaptainConstants.registryServiceName, [
{
protocol: 'tcp',
containerPort: 5000,
hostPort: CaptainConstants.configs.registrySubDomainPort,
},
], myNodeId, [
{
containerPath: '/cert-files',
hostPath: CaptainConstants.letsEncryptEtcPath,
},
{
containerPath: '/var/lib/registry',
hostPath: CaptainConstants.registryPathOnHost,
},
{
containerPath: '/etc/auth',
hostPath: CaptainConstants.registryAuthPathOnHost,
},
], [
{
key: 'REGISTRY_HTTP_TLS_CERTIFICATE',
value: '/cert-files/live/' +
CaptainConstants.registrySubDomain +
'.' +
dataStore.getRootDomain() +
'/fullchain.pem',
},
{
key: 'REGISTRY_HTTP_TLS_KEY',
value: '/cert-files/live/' +
CaptainConstants.registrySubDomain +
'.' +
dataStore.getRootDomain() +
'/privkey.pem',
},
{
key: 'REGISTRY_AUTH',
value: 'htpasswd',
},
{
key: 'REGISTRY_AUTH_HTPASSWD_REALM',
value: 'Registry Realm',
},
{
key: 'REGISTRY_AUTH_HTPASSWD_PATH',
value: '/etc/auth',
},
], undefined);
}
return Promise.resolve()
.then(function () {
const authContent = CaptainConstants.captainRegistryUsername +
':' +
bcrypt.hashSync(password, bcrypt.genSaltSync(5));
return fs.outputFile(CaptainConstants.registryAuthPathOnHost, authContent);
})
.then(function () {
return dockerApi.isServiceRunningByName(CaptainConstants.registryServiceName);
})
.then(function (isRunning) {
if (isRunning) {
Logger.d('Captain Registry is already running.. ');
return dockerApi.getNodeIdByServiceName(CaptainConstants.registryServiceName, 0);
}
else {
Logger.d('No Captain Registry service is running. Creating one...');
return createRegistryServiceOnNode().then(function () {
return myNodeId;
});
}
})
.then(function (nodeId) {
if (nodeId !== myNodeId) {
Logger.d('Captain Registry is running on a different node. Removing...');
return dockerApi
.removeServiceByName(CaptainConstants.registryServiceName)
.then(function () {
Logger.d('Creating Registry on this node...');
return createRegistryServiceOnNode().then(function () {
return true;
});
});
}
else {
return true;
}
});
}
}
module.exports = SelfHostedDockerRegistry;
//# sourceMappingURL=SelfHostedDockerRegistry.js.map
@@ -0,0 +1 @@
{"version":3,"file":"SelfHostedDockerRegistry.js","sourceRoot":"","sources":["../../../src/user/system/SelfHostedDockerRegistry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
"use strict";
const request = require("request");
const ApiStatusCodes = require("../api/ApiStatusCodes");
const Logger = require("./Logger");
function getTagsForImage(imageBaseName, url, allTags) {
if (!url) {
url =
'https://hub.docker.com/v2/repositories/' + imageBaseName + '/tags';
}
return new Promise(function (resolve, reject) {
request(url, function (error, response, body) {
if (error || !body) {
Logger.e(error);
reject(error);
return;
}
try {
// Sometimes Docker server is down and it crashes Captain!
body = JSON.parse(body);
}
catch (e) {
Logger.e(e);
}
let results;
if (body) {
results = body.results;
}
if (!results) {
Logger.e('NO RESULT');
reject(new Error('NO RESULT'));
return;
}
if (!allTags) {
allTags = [];
}
for (let idx = 0; idx < results.length; idx++) {
allTags.push(results[idx].name);
}
if (body.next) {
resolve(getTagsForImage(imageBaseName, body.next, allTags));
return;
}
resolve(allTags);
});
});
}
function firstEndsWithSecond(str1, str2) {
if (!str1 || !str2) {
throw new Error('Str1 or Str2 are null ' + !str1 + ' ' + !str2);
}
const idx = str1.indexOf(str2);
return idx >= 0 && idx + str2.length === str1.length;
}
function isEmpty(obj) {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
return false;
}
}
return true;
}
class TemplateHelperVersionPrinter {
constructor() {
this.cachedImageTags = {};
}
getDockerVersionsForTemplateName(templateObj) {
const self = this;
if (isEmpty(this.cachedImageTags)) {
throw ApiStatusCodes.createError(ApiStatusCodes.STATUS_ERROR_GENERIC, 'Please wait about 30 seconds, then try again.');
}
const tags = self.cachedImageTags[templateObj.dockerHubImageName];
const dockerVersions = [];
for (let i = 0; i < tags.length; i++) {
const t = tags[i];
if (firstEndsWithSecond(t, templateObj.tagSuffix)) {
dockerVersions.push(t.substring(0, t.length - templateObj.tagSuffix.length));
}
}
return dockerVersions;
}
printAvailableImageTagsForReadme(templates) {
const self = this;
self.cachedImageTags = {};
const tempCache = {};
for (let i = 0; i < templates.length; i++) {
const currentImageName = templates[i].dockerHubImageName;
getTagsForImage(currentImageName, undefined, undefined)
.then(function (tags) {
tempCache[currentImageName] = tags;
let isAllDone = true;
for (let j = 0; j < templates.length; j++) {
const imageName = templates[j].dockerHubImageName;
if (!tempCache[imageName]) {
isAllDone = false;
}
}
if (isAllDone) {
Logger.d('Template Cache Updated!');
self.cachedImageTags = tempCache;
// Used for README
for (let tempIdx = 0; tempIdx < templates.length; tempIdx++) {
Logger.d(' ');
Logger.d(templates[tempIdx].templateName + '/');
Logger.d(self
.getDockerVersionsForTemplateName(templates[tempIdx])
.join(', '));
Logger.d(' ');
}
}
})
.catch(function (error) {
Logger.e(error);
});
}
}
}
module.exports = TemplateHelperVersionPrinter;
//# sourceMappingURL=TemplateHelperVersionPrinter.js.map
@@ -0,0 +1 @@
{"version":3,"file":"TemplateHelperVersionPrinter.js","sourceRoot":"","sources":["../../src/utils/TemplateHelperVersionPrinter.ts"],"names":[],"mappings":";AAAA,mCAAmC;AAEnC,wDAAwD;AACxD,mCAAmC;AAInC,SAAS,eAAe,CACpB,aAAqB,EACrB,GAAuB,EACvB,OAA6B;IAE7B,IAAI,CAAC,GAAG,EAAE;QACN,GAAG;YACC,yCAAyC,GAAG,aAAa,GAAG,OAAO,CAAA;KAC1E;IAED,OAAO,IAAI,OAAO,CAAW,UAAS,OAAO,EAAE,MAAM;QACjD,OAAO,CACH,GAAI,EAEJ,UAAS,KAAK,EAAE,QAAQ,EAAE,IAAI;YAC1B,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE;gBAChB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;gBACf,MAAM,CAAC,KAAK,CAAC,CAAA;gBACb,OAAM;aACT;YAED,IAAI;gBACA,0DAA0D;gBAC1D,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;aAC1B;YAAC,OAAO,CAAC,EAAE;gBACR,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;aACd;YAED,IAAI,OAAY,CAAA;YAEhB,IAAI,IAAI,EAAE;gBACN,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;aACzB;YAED,IAAI,CAAC,OAAO,EAAE;gBACV,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;gBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,CAAA;gBAC9B,OAAM;aACT;YAED,IAAI,CAAC,OAAO,EAAE;gBACV,OAAO,GAAG,EAAE,CAAA;aACf;YAED,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;gBAC3C,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;aAClC;YAED,IAAI,IAAI,CAAC,IAAI,EAAE;gBACX,OAAO,CAAC,eAAe,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;gBAC3D,OAAM;aACT;YAED,OAAO,CAAC,OAAO,CAAC,CAAA;QACpB,CAAC,CACJ,CAAA;IACL,CAAC,CAAC,CAAA;AACN,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY,EAAE,IAAY;IACnD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE;QAChB,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;KAClE;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,CAAA;AACxD,CAAC;AAED,SAAS,OAAO,CAAC,GAAQ;IACrB,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE;QACnB,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;YACzB,OAAO,KAAK,CAAA;SACf;KACJ;IACD,OAAO,IAAI,CAAA;AACf,CAAC;AAID,MAAM,4BAA4B;IAG9B;QACI,IAAI,CAAC,eAAe,GAAG,EAAE,CAAA;IAC7B,CAAC;IAED,gCAAgC,CAAC,WAAsB;QACnD,MAAM,IAAI,GAAG,IAAI,CAAA;QAEjB,IAAI,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE;YAC/B,MAAM,cAAc,CAAC,WAAW,CAC5B,cAAc,CAAC,oBAAoB,EACnC,+CAA+C,CAClD,CAAA;SACJ;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAA;QAEjE,MAAM,cAAc,GAAG,EAAE,CAAA;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAClC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,IAAI,mBAAmB,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE;gBAC/C,cAAc,CAAC,IAAI,CACf,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAC1D,CAAA;aACJ;SACJ;QAED,OAAO,cAAc,CAAA;IACzB,CAAC;IAED,gCAAgC,CAAC,SAAsB;QACnD,MAAM,IAAI,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC,eAAe,GAAG,EAAE,CAAA;QAEzB,MAAM,SAAS,GAAe,EAAE,CAAA;QAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACvC,MAAM,gBAAgB,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAA;YAExD,eAAe,CAAC,gBAAgB,EAAE,SAAS,EAAE,SAAS,CAAC;iBAClD,IAAI,CAAC,UAAS,IAAI;gBACf,SAAS,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAA;gBAElC,IAAI,SAAS,GAAG,IAAI,CAAA;gBAEpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;oBACvC,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAA;oBACjD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;wBACvB,SAAS,GAAG,KAAK,CAAA;qBACpB;iBACJ;gBAED,IAAI,SAAS,EAAE;oBACX,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAA;oBAEnC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAA;oBAEhC,kBAAkB;oBAClB,KACI,IAAI,OAAO,GAAG,CAAC,EACf,OAAO,GAAG,SAAS,CAAC,MAAM,EAC1B,OAAO,EAAE,EACX;wBACE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;wBACb,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,YAAY,GAAG,GAAG,CAAC,CAAA;wBAC/C,MAAM,CAAC,CAAC,CACJ,IAAI;6BACC,gCAAgC,CAC7B,SAAS,CAAC,OAAO,CAAC,CACrB;6BACA,IAAI,CAAC,IAAI,CAAC,CAClB,CAAA;wBACD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;qBAChB;iBACJ;YACL,CAAC,CAAC;iBACD,KAAK,CAAC,UAAS,KAAK;gBACjB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YACnB,CAAC,CAAC,CAAA;SACT;IACL,CAAC;CACJ;AAED,iBAAS,4BAA4B,CAAA"}
+1 -1
View File
@@ -6,7 +6,7 @@ import cookieParser = require('cookie-parser')
import bodyParser = require('body-parser')
import httpProxyImport = require('http-proxy')
import CaptainManager = require('./user/CaptainManager')
import CaptainManager = require('./user/system/CaptainManager')
import BaseApi = require('./api/BaseApi')
import ApiStatusCodes = require('./api/ApiStatusCodes')
import Injector = require('./injection/Injector')
+1 -1
View File
@@ -1,7 +1,7 @@
import DataStoreProvider = require('../datastore/DataStoreProvider')
import Authenticator = require('../user/Authenticator')
import CaptainConstants = require('../utils/CaptainConstants')
import CaptainManager = require('../user/CaptainManager')
import CaptainManager = require('../user/system/CaptainManager')
import ServiceManager = require('../user/ServiceManager')
import DockerApiProvider = require('../docker/DockerApi')
import BaseApi = require('../api/BaseApi')
@@ -2,7 +2,7 @@ import express = require('express')
import BaseApi = require('../../api/BaseApi')
import ApiStatusCodes = require('../../api/ApiStatusCodes')
import Logger = require('../../utils/Logger')
import CaptainManager = require('../../user/CaptainManager')
import CaptainManager = require('../../user/system/CaptainManager')
import Validator = require('validator')
import CaptainConstants = require('../../utils/CaptainConstants')
import InjectionExtractor = require('../../injection/InjectionExtractor')
@@ -2,7 +2,7 @@ import express = require('express')
import BaseApi = require('../../api/BaseApi')
import ApiStatusCodes = require('../../api/ApiStatusCodes')
import Logger = require('../../utils/Logger')
import CaptainManager = require('../../user/CaptainManager')
import CaptainManager = require('../../user/system/CaptainManager')
import Validator = require('validator')
import SystemRouteSelfHostRegistry = require('./SystemRouteSelfHostRegistry')
import CaptainConstants = require('../../utils/CaptainConstants')
+1 -1
View File
@@ -5,7 +5,7 @@ import bcrypt = require('bcryptjs')
import ApiStatusCodes = require('../api/ApiStatusCodes')
import EnvVar = require('../utils/EnvVars')
import CaptainManager = require('./CaptainManager')
import CaptainManager = require('./system/CaptainManager')
import CaptainConstants = require('../utils/CaptainConstants')
import Logger = require('../utils/Logger')
import DataStoreProvider = require('../datastore/DataStoreProvider')
+2 -2
View File
@@ -1,7 +1,7 @@
import Logger = require('../utils/Logger')
import CaptainConstants = require('../utils/CaptainConstants')
import CaptainManager = require('./CaptainManager')
import LoadBalancerManager = require('./LoadBalancerManager')
import CaptainManager = require('./system/CaptainManager')
import LoadBalancerManager = require('./system/LoadBalancerManager')
import DockerApi = require('../docker/DockerApi')
import DataStore = require('../datastore/DataStore')
import ApiStatusCodes = require('../api/ApiStatusCodes')
+1 -1
View File
@@ -4,7 +4,7 @@ import ApiStatusCodes = require('../api/ApiStatusCodes')
import Logger = require('../utils/Logger')
import CaptainConstants = require('../utils/CaptainConstants')
import { ITemplate } from '../models/OtherTypes'
import TemplateHelperVersionPrinter = require('./TemplateHelperVersionPrinter')
import TemplateHelperVersionPrinter = require('../utils/TemplateHelperVersionPrinter')
class TemplateHelper {
private templates: ITemplate[]
@@ -2,17 +2,17 @@ import uuid = require('uuid/v4')
import SshClientImport = require('ssh2')
import request = require('request')
import fs = require('fs-extra')
import CaptainConstants = require('../utils/CaptainConstants')
import Logger = require('../utils/Logger')
import CaptainConstants = require('../../utils/CaptainConstants')
import Logger = require('../../utils/Logger')
import LoadBalancerManager = require('./LoadBalancerManager')
import EnvVars = require('../utils/EnvVars')
import Encryptor = require('../utils/Encryptor')
import EnvVars = require('../../utils/EnvVars')
import Encryptor = require('../../utils/Encryptor')
import CertbotManager = require('./CertbotManager')
import DockerRegistry = require('./DockerRegistry')
import ApiStatusCodes = require('../api/ApiStatusCodes')
import DataStoreProvider = require('../datastore/DataStoreProvider')
import DataStore = require('../datastore/DataStore')
import DockerApi = require('../docker/DockerApi')
import SelfHostedDockerRegistry = require('./SelfHostedDockerRegistry')
import ApiStatusCodes = require('../../api/ApiStatusCodes')
import DataStoreProvider = require('../../datastore/DataStoreProvider')
import DataStore = require('../../datastore/DataStore')
import DockerApi = require('../../docker/DockerApi')
const DEBUG_SALT = 'THIS IS NOT A REAL CERTIFICATE'
const SshClient = SshClientImport.Client
@@ -30,7 +30,7 @@ class CaptainManager {
private dockerApi: DockerApi
private certbotManager: CertbotManager
private loadBalancerManager: LoadBalancerManager
private dockerRegistry: DockerRegistry
private dockerRegistry: SelfHostedDockerRegistry
private myNodeId: string | undefined
private inited: boolean
private waitUntilRestarted: boolean
@@ -52,7 +52,7 @@ class CaptainManager {
this.certbotManager,
this.dataStore
)
this.dockerRegistry = new DockerRegistry(
this.dockerRegistry = new SelfHostedDockerRegistry(
dockerApi,
this.dataStore,
this.certbotManager,
@@ -1,9 +1,9 @@
import CaptainConstants = require('../utils/CaptainConstants')
import Logger = require('../utils/Logger')
import CaptainConstants = require('../../utils/CaptainConstants')
import Logger = require('../../utils/Logger')
import fs = require('fs-extra')
import uuid = require('uuid/v4')
import ApiStatusCodes = require('../api/ApiStatusCodes')
import DockerApi = require('../docker/DockerApi')
import ApiStatusCodes = require('../../api/ApiStatusCodes')
import DockerApi = require('../../docker/DockerApi')
const CAPTAIN_WEBROOT_PATH_CERTBOT = '/captain-webroot'
@@ -1,14 +1,14 @@
import ejs = require('ejs')
import CaptainConstants = require('../utils/CaptainConstants')
import Logger = require('../utils/Logger')
import CaptainConstants = require('../../utils/CaptainConstants')
import Logger = require('../../utils/Logger')
import fs = require('fs-extra')
import uuid = require('uuid/v4')
import request = require('request')
import ApiStatusCodes = require('../api/ApiStatusCodes')
import DockerApi = require('../docker/DockerApi')
import DataStore = require('../datastore/DataStore')
import ApiStatusCodes = require('../../api/ApiStatusCodes')
import DockerApi = require('../../docker/DockerApi')
import DataStore = require('../../datastore/DataStore')
import CertbotManager = require('./CertbotManager')
import { AnyError } from '../models/OtherTypes'
import { AnyError } from '../../models/OtherTypes'
const defaultPageTemplate = fs
.readFileSync(__dirname + '/../../template/default-page.ejs')
@@ -1,17 +1,17 @@
import CaptainConstants = require('../utils/CaptainConstants')
import Logger = require('../utils/Logger')
import EnvVars = require('../utils/EnvVars')
import CaptainConstants = require('../../utils/CaptainConstants')
import Logger = require('../../utils/Logger')
import EnvVars = require('../../utils/EnvVars')
import fs = require('fs-extra')
import uuid = require('uuid/v4')
import ApiStatusCodes = require('../api/ApiStatusCodes')
import ApiStatusCodes = require('../../api/ApiStatusCodes')
import bcrypt = require('bcryptjs')
import DockerApi = require('../docker/DockerApi')
import DataStore = require('../datastore/DataStore')
import CertbotManager = require('../user/CertbotManager')
import LoadBalancerManager = require('../user/LoadBalancerManager')
import CaptainManager = require('../user/CaptainManager')
import DockerApi = require('../../docker/DockerApi')
import DataStore = require('../../datastore/DataStore')
import CertbotManager = require('./CertbotManager')
import LoadBalancerManager = require('./LoadBalancerManager')
import CaptainManager = require('./CaptainManager')
class DockerRegistry {
class SelfHostedDockerRegistry {
constructor(
private dockerApi: DockerApi,
private dataStore: DataStore,
@@ -215,4 +215,4 @@ class DockerRegistry {
}
}
export = DockerRegistry
export = SelfHostedDockerRegistry
@@ -1,8 +1,8 @@
import request = require('request')
import fs = require('fs-extra')
import ApiStatusCodes = require('../api/ApiStatusCodes')
import Logger = require('../utils/Logger')
import CaptainConstants = require('../utils/CaptainConstants')
import Logger = require('./Logger')
import CaptainConstants = require('./CaptainConstants')
import { ITemplate } from '../models/OtherTypes'
function getTagsForImage(