navy
Version:
Quick and powerful development environments using Docker and Docker Compose
136 lines (133 loc) • 5.22 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.reconfigureHTTPProxy = reconfigureHTTPProxy;
exports.resolveDockerSocketPath = resolveDockerSocketPath;
exports.resolveProxyEnv = resolveProxyEnv;
exports.resolveProxyEnvAllowlist = resolveProxyEnvAllowlist;
exports.resolveProxyEnvFromNavyFile = resolveProxyEnvFromNavyFile;
exports.resolveProxyImage = resolveProxyImage;
var _os = _interopRequireDefault(require("os"));
var _path = _interopRequireDefault(require("path"));
var _jsYaml = _interopRequireDefault(require("js-yaml"));
var _dockerClient = _interopRequireDefault(require("./util/docker-client"));
var _fs = _interopRequireDefault(require("fs"));
var _https = require("./util/https");
var _execAsync = require("./util/exec-async");
var _driverLogging = require("./driver-logging");
var _navy = require("./navy");
const DEFAULT_PROXY_IMAGE = 'navycloud/navy-proxy';
const DEFAULT_DOCKER_SOCKET = '/var/run/docker.sock';
function resolveProxyImage(navyFile) {
return process.env.NAVY_HTTP_PROXY_IMAGE || navyFile && navyFile.httpProxyImage || DEFAULT_PROXY_IMAGE;
}
function resolveProxyEnvFromNavyFile(navyFile) {
if (!navyFile) return {};
const raw = navyFile.httpProxyEnv;
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {};
const result = {};
for (const key of Object.keys(raw)) {
const value = raw[key];
if (value === null || value === undefined) continue;
const coerced = String(value);
if (coerced === '') continue;
result[key] = coerced;
}
return result;
}
function resolveProxyEnvAllowlist() {
const allowlist = process.env.NAVY_HTTP_PROXY_ENV;
if (!allowlist) return {};
const seen = new Set();
const result = {};
for (const rawName of allowlist.split(',')) {
const name = rawName.trim();
if (!name || seen.has(name)) continue;
seen.add(name);
const value = process.env[name];
if (typeof value !== 'string' || value === '') continue;
result[name] = value;
}
return result;
}
function resolveProxyEnv(navyFile) {
const merged = {
...resolveProxyEnvFromNavyFile(navyFile),
...resolveProxyEnvAllowlist()
};
if (Object.keys(merged).length === 0) return null;
return merged;
}
// Resolve the host path to the Docker socket. The proxy container needs to
// read events from the same daemon as the rest of navy, so we honour
// DOCKER_HOST when it points at a unix socket (e.g. on CI where
// `docker/setup-docker-action` puts the daemon on a custom path) and fall
// back to the conventional `/var/run/docker.sock` otherwise.
function resolveDockerSocketPath() {
const dockerHost = process.env.DOCKER_HOST;
if (dockerHost && dockerHost.indexOf('unix://') === 0) {
const socketPath = dockerHost.slice('unix://'.length);
if (socketPath) return socketPath;
}
return DEFAULT_DOCKER_SOCKET;
}
async function updateComposeConfig(navies, navyFile) {
const allNetworks = await _dockerClient.default.listNetworks();
const networks = allNetworks.filter(net => net.Name.indexOf('_') !== -1) // is docker-compose network?
.filter(net => {
for (const navy of navies) {
if (net.Name.indexOf(navy + '_') === 0) {
return true;
}
}
return false;
});
const networksConfig = {};
networks.forEach(net => networksConfig[net.Name] = {
external: true
});
const ports = ['80:80'];
const volumes = [`${resolveDockerSocketPath()}:/tmp/docker.sock:ro`];
// Enable HTTPS for services that
// match crt file names in tlsRootCaDir
const certsPath = await (0, _https.getCertsPath)(true);
if (certsPath) {
ports.push('443:443');
volumes.push(`${certsPath}:/etc/nginx/certs`);
volumes.push(`${certsPath}:/etc/nginx/dhparam`); // to persist DH params
}
const proxyEnv = resolveProxyEnv(navyFile);
const config = {
version: '2',
services: {
'nginx-proxy': {
image: resolveProxyImage(navyFile),
ports,
networks: networks.map(net => net.Name),
volumes,
...(proxyEnv ? {
environment: proxyEnv
} : {}),
restart: 'always'
}
},
networks: networksConfig
};
_fs.default.writeFileSync(_path.default.join(_os.default.tmpdir(), 'navyinternaldockercompose.yml'), _jsYaml.default.dump(config));
}
async function reconfigureHTTPProxy(opts = {}) {
const navyInternalYamlFile = _path.default.join(_os.default.tmpdir(), 'navyinternaldockercompose.yml');
if (opts.restart) {
// proxy needs to be recreated to detect changes (deletes) in /etc/nginx/certs
if (_fs.default.existsSync(navyInternalYamlFile)) {
(0, _driverLogging.log)('Restarting HTTP proxy...');
await (0, _execAsync.execAsync)('docker compose', ['-f', navyInternalYamlFile, '-p', 'navyinternal', 'rm', '-s', '-f', 'nginx-proxy']);
}
}
if (!opts.navies) opts.navies = await (0, _navy.getLaunchedNavyNames)();
await updateComposeConfig(opts.navies, opts.navyFile);
(0, _driverLogging.log)('Configuring HTTP proxy...');
await (0, _execAsync.execAsync)('docker compose', ['-f', navyInternalYamlFile, '-p', 'navyinternal', 'up', '-d']);
}