Files
cloudron-box/src/dockerproxy.js

95 lines
3.1 KiB
JavaScript
Raw Normal View History

2018-08-13 21:10:53 +02:00
'use strict';
exports = module.exports = {
start: start,
stop: stop
};
var assert = require('assert'),
2018-08-13 22:14:56 +02:00
bodyParser = require('body-parser'),
2018-08-13 21:10:53 +02:00
config = require('./config.js'),
2018-08-13 22:06:28 +02:00
debug = require('debug')('box:dockerproxy'),
2018-08-13 22:14:56 +02:00
http = require('http'),
net = require('net');
2018-08-13 21:10:53 +02:00
var gServer = null;
var gJSONParser = bodyParser.json();
2018-08-13 21:10:53 +02:00
function start(callback) {
assert.strictEqual(typeof callback, 'function');
2018-08-13 22:14:56 +02:00
function authorized(req, res) {
// TODO add here some authorization
// - block apps not using the docker addon
// - block calls regarding platform containers
// - only allow managing and inspection of containers belonging to the app
2018-08-13 22:14:56 +02:00
return true;
2018-08-13 21:10:53 +02:00
}
debug(`startDockerProxy: starting proxy on port ${config.get('dockerProxyPort')}`);
gServer = http.createServer(function (req, res) {
if (!authorized(req, res)) return;
2018-08-13 21:10:53 +02:00
var options = {
socketPath: '/var/run/docker.sock',
method: req.method,
path: req.url,
2018-08-13 22:14:56 +02:00
headers: req.headers
};
2018-08-13 21:10:53 +02:00
var dockerRequest = http.request(options, function (dockerResponse) {
res.writeHead(dockerResponse.statusCode, dockerResponse.headers);
2018-08-13 22:14:56 +02:00
// Force node to send out the headers, this is required for the /container/wait api to make the docker cli proceed
res.write(' ');
dockerResponse.on('error', function (error) { console.error('dockerResponse error:', error); });
2018-08-13 21:10:53 +02:00
dockerResponse.pipe(res, { end: true });
});
2018-08-13 22:14:56 +02:00
req.on('error', function (error) { console.error('req error:', error); });
if (req.method === 'POST' && req.url.match(/\/containers\/create/)) {
gJSONParser(req, res, function () {
// overwrite the network the container lives in
req.body.HostConfig.NetworkMode = 'cloudron';
var plainBody = JSON.stringify(req.body);
dockerRequest.setHeader('Content-Length', Buffer.byteLength(plainBody));
dockerRequest.end(plainBody);
});
} else if (!req.readable) {
2018-08-13 21:10:53 +02:00
dockerRequest.end();
} else {
req.pipe(dockerRequest, { end: true });
}
}).listen(config.get('dockerProxyPort'), callback);
2018-08-13 22:14:56 +02:00
gServer.on('upgrade', function (req, client, head) {
// Create a new tcp connection to the TCP server
var remote = net.connect('/var/run/docker.sock', function () {
// two-way pipes between client and docker daemon
client.pipe(remote).pipe(client);
// resend the upgrade event to the docker daemon, so it responds with the proper message through the pipes
remote.write(req.method + ' ' + req.url + ' HTTP/1.1\r\n' +
`Host: ${req.headers.host}\r\n` +
'Connection: Upgrade\r\n' +
'Upgrade: tcp\r\n' +
'\r\n'
);
});
});
2018-08-13 21:10:53 +02:00
}
function stop(callback) {
assert.strictEqual(typeof callback, 'function');
if (gServer) gServer.close();
callback();
}