Merge pull request #645 from embark-framework/features/defaultHost

docker awareness
This commit is contained in:
Iuri Matias 2018-07-27 11:04:05 -04:00 committed by GitHub
commit b93f3613bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 95 additions and 21 deletions

View File

@ -7,6 +7,8 @@ const utils = require('../../utils/utils.js');
const GethCommands = require('./geth_commands.js'); const GethCommands = require('./geth_commands.js');
const {defaultHost, dockerHostSwap} = require('../../utils/host');
/*eslint complexity: ["error", 36]*/ /*eslint complexity: ["error", 36]*/
var Blockchain = function(options) { var Blockchain = function(options) {
this.blockchainConfig = options.blockchainConfig; this.blockchainConfig = options.blockchainConfig;
@ -26,7 +28,7 @@ var Blockchain = function(options) {
genesisBlock: this.blockchainConfig.genesisBlock || false, genesisBlock: this.blockchainConfig.genesisBlock || false,
datadir: this.blockchainConfig.datadir || false, datadir: this.blockchainConfig.datadir || false,
mineWhenNeeded: this.blockchainConfig.mineWhenNeeded || false, mineWhenNeeded: this.blockchainConfig.mineWhenNeeded || false,
rpcHost: this.blockchainConfig.rpcHost || 'localhost', rpcHost: dockerHostSwap(this.blockchainConfig.rpcHost) || defaultHost,
rpcPort: this.blockchainConfig.rpcPort || 8545, rpcPort: this.blockchainConfig.rpcPort || 8545,
rpcCorsDomain: this.blockchainConfig.rpcCorsDomain || false, rpcCorsDomain: this.blockchainConfig.rpcCorsDomain || false,
networkId: this.blockchainConfig.networkId || 1337, networkId: this.blockchainConfig.networkId || 1337,
@ -39,7 +41,7 @@ var Blockchain = function(options) {
bootnodes: this.blockchainConfig.bootnodes || "", bootnodes: this.blockchainConfig.bootnodes || "",
rpcApi: (this.blockchainConfig.rpcApi || ['eth', 'web3', 'net', 'debug']), rpcApi: (this.blockchainConfig.rpcApi || ['eth', 'web3', 'net', 'debug']),
wsRPC: (this.blockchainConfig.wsRPC === undefined) || this.blockchainConfig.wsRPC, wsRPC: (this.blockchainConfig.wsRPC === undefined) || this.blockchainConfig.wsRPC,
wsHost: this.blockchainConfig.wsHost || 'localhost', wsHost: dockerHostSwap(this.blockchainConfig.wsHost) || defaultHost,
wsPort: this.blockchainConfig.wsPort || 8546, wsPort: this.blockchainConfig.wsPort || 8546,
wsOrigins: this.blockchainConfig.wsOrigins || false, wsOrigins: this.blockchainConfig.wsOrigins || false,
wsApi: (this.blockchainConfig.wsApi || ['eth', 'web3', 'net', 'shh', 'debug']), wsApi: (this.blockchainConfig.wsApi || ['eth', 'web3', 'net', 'shh', 'debug']),

View File

@ -3,6 +3,7 @@ let shelljs = require('shelljs');
let proxy = require('../core/proxy'); let proxy = require('../core/proxy');
const Ipc = require('../core/ipc'); const Ipc = require('../core/ipc');
const constants = require('../constants.json'); const constants = require('../constants.json');
const {defaultHost, dockerHostSwap} = require('../utils/host');
class Simulator { class Simulator {
constructor(options) { constructor(options) {
@ -16,7 +17,7 @@ class Simulator {
const ganache = path.join(__dirname, '../../node_modules/.bin/ganache-cli'); const ganache = path.join(__dirname, '../../node_modules/.bin/ganache-cli');
let useProxy = this.blockchainConfig.proxy || false; let useProxy = this.blockchainConfig.proxy || false;
let host = (options.host || this.blockchainConfig.rpcHost || 'localhost'); let host = (dockerHostSwap(options.host || this.blockchainConfig.rpcHost) || defaultHost);
let port = (options.port || this.blockchainConfig.rpcPort || 8545); let port = (options.port || this.blockchainConfig.rpcPort || 8545);
cmds.push("-p " + (port + (useProxy ? constants.blockchain.servicePortOnProxy : 0))); cmds.push("-p " + (port + (useProxy ? constants.blockchain.servicePortOnProxy : 0)));

View File

@ -5,6 +5,7 @@ const utils = require('../utils/utils.js');
const path = require('path'); const path = require('path');
const deepEqual = require('deep-equal'); const deepEqual = require('deep-equal');
const constants = require('../constants'); const constants = require('../constants');
const {canonicalHost, defaultHost} = require('../utils/host');
var Config = function(options) { var Config = function(options) {
const self = this; const self = this;
@ -106,6 +107,9 @@ Config.prototype._updateBlockchainCors = function(){
// remove /ipfs or /bzz: from getUrl if it's there // remove /ipfs or /bzz: from getUrl if it's there
let getUrlParts = storageConfig.upload.getUrl.split('/'); let getUrlParts = storageConfig.upload.getUrl.split('/');
getUrlParts = getUrlParts.slice(0, 3); getUrlParts = getUrlParts.slice(0, 3);
let host = canonicalHost(getUrlParts[2].split(':')[0]);
let port = getUrlParts[2].split(':')[1];
getUrlParts[2] = port ? [host, port].join(':') : host;
corsParts.push(getUrlParts.join('/')); corsParts.push(getUrlParts.join('/'));
} }
// use our modified getUrl or in case it wasn't specified, use a built url // use our modified getUrl or in case it wasn't specified, use a built url
@ -259,7 +263,7 @@ Config.prototype.loadStorageConfigFile = function() {
"upload": { "upload": {
"provider": "ipfs", "provider": "ipfs",
"protocol": "http", "protocol": "http",
"host": "localhost", "host" : defaultHost,
"port": 5001, "port": 5001,
"getUrl": "http://localhost:8080/ipfs/" "getUrl": "http://localhost:8080/ipfs/"
}, },
@ -297,7 +301,9 @@ Config.prototype.loadCommunicationConfigFile = function() {
"provider": "whisper", "provider": "whisper",
"available_providers": ["whisper"], "available_providers": ["whisper"],
"connection": { "connection": {
"host": "localhost", "port": 8546, "type": "ws" "host": defaultHost,
"port": 8546,
"type": "ws"
} }
} }
}; };
@ -309,7 +315,9 @@ Config.prototype.loadCommunicationConfigFile = function() {
Config.prototype.loadWebServerConfigFile = function() { Config.prototype.loadWebServerConfigFile = function() {
var configObject = { var configObject = {
"enabled": true, "host": "localhost", "port": 8000 "enabled": true,
"host": defaultHost,
"port": 8000
}; };
let configFilePath = this._getFileOrOject(this.configDir, 'webserver', 'webserver'); let configFilePath = this._getFileOrOject(this.configDir, 'webserver', 'webserver');

View File

@ -6,6 +6,8 @@ let commList = {};
let transactions = {}; let transactions = {};
let receipts = {}; let receipts = {};
const {canonicalHost, defaultHost} = require('../utils/host');
const parseRequest = function(reqBody){ const parseRequest = function(reqBody){
let jsonO; let jsonO;
try { try {
@ -61,7 +63,7 @@ const parseResponse = function(ipc, resBody){
exports.serve = function(ipc, host, port, ws){ exports.serve = function(ipc, host, port, ws){
let proxy = httpProxy.createProxyServer({ let proxy = httpProxy.createProxyServer({
target: { target: {
host, host: canonicalHost(host),
port: port + constants.blockchain.servicePortOnProxy port: port + constants.blockchain.servicePortOnProxy
}, },
ws: ws ws: ws
@ -120,6 +122,6 @@ exports.serve = function(ipc, host, port, ws){
}); });
} }
server.listen(port); server.listen(port, defaultHost);
return server; return server;
}; };

View File

@ -1,3 +1,4 @@
var {canonicalHost} = require('../../utils/host.js');
var utils = require('../../utils/utils.js'); var utils = require('../../utils/utils.js');
var Server = require('./server.js'); var Server = require('./server.js');
@ -26,7 +27,7 @@ class WebServer {
} }
setServiceCheck() { setServiceCheck() {
let url = 'http://' + this.host + ':' + this.port; let url = 'http://' + canonicalHost(this.host) + ':' + this.port;
this.events.request("services:register", 'Webserver', function (cb) { this.events.request("services:register", 'Webserver', function (cb) {
utils.checkIsAvailable(url, function (available) { utils.checkIsAvailable(url, function (available) {

View File

@ -1,19 +1,23 @@
let finalhandler = require('finalhandler'); let finalhandler = require('finalhandler');
let http = require('http'); let http = require('http');
let serveStatic = require('serve-static'); let serveStatic = require('serve-static');
const {canonicalHost, defaultHost, dockerHostSwap} = require('../../utils/host');
require('http-shutdown').extend(); require('http-shutdown').extend();
class Server { class Server {
constructor(options) { constructor(options) {
this.dist = options.dist || 'dist/'; this.dist = options.dist || 'dist/';
this.port = options.port || 8000; this.port = options.port || 8000;
this.hostname = options.host || 'localhost'; this.hostname = dockerHostSwap(options.host) || defaultHost;
this.logger = options.logger; this.logger = options.logger;
} }
start(callback) { start(callback) {
if (this.server && this.server.listening) { if (this.server && this.server.listening) {
this.logger.warn(__("a webserver is already running at") + " " + ("http://" + this.hostname + ":" + this.port).bold.underline.green); this.logger.warn(__("a webserver is already running at") +
" " +
("http://" + canonicalHost(this.hostname) +
":" + this.port).bold.underline.green);
if (callback) { if (callback) {
callback(); callback();
} }
@ -25,7 +29,10 @@ class Server {
serve(req, res, finalhandler(req, res)); serve(req, res, finalhandler(req, res));
}).withShutdown(); }).withShutdown();
this.logger.info(__("webserver available at") + " " + ("http://" + this.hostname + ":" + this.port).bold.underline.green); this.logger.info(__("webserver available at") +
" " +
("http://" + canonicalHost(this.hostname) +
":" + this.port).bold.underline.green);
this.server.listen(this.port, this.hostname); this.server.listen(this.port, this.hostname);
if (callback) { if (callback) {
callback(); callback();

View File

@ -2,6 +2,8 @@ let utils = require('../../utils/utils.js');
let fs = require('../../core/fs.js'); let fs = require('../../core/fs.js');
let Web3 = require('web3'); let Web3 = require('web3');
const {canonicalHost, defaultHost} = require('../../utils/host');
class Whisper { class Whisper {
constructor(embark, _options) { constructor(embark, _options) {
@ -74,7 +76,7 @@ class Whisper {
// todo: make the add code a function as well // todo: make the add code a function as well
let config = JSON.stringify({ let config = JSON.stringify({
server: connection.host || 'localhost', server: canonicalHost(connection.host || defaultHost),
port: connection.port || '8546', port: connection.port || '8546',
type: connection.type || 'ws' type: connection.type || 'ws'
}); });

View File

@ -4,6 +4,7 @@ const utils = require('../../utils/utils');
const ProcessLauncher = require('../../process/processLauncher'); const ProcessLauncher = require('../../process/processLauncher');
const constants = require('../../constants'); const constants = require('../../constants');
const StorageUtils = require('./storageUtils'); const StorageUtils = require('./storageUtils');
const {canonicalHost} = require('../../utils/host');
class StorageProcessesLauncher { class StorageProcessesLauncher {
constructor(options) { constructor(options) {
@ -46,6 +47,9 @@ class StorageProcessesLauncher {
// remove /ipfs or /bzz: from getUrl if it's there // remove /ipfs or /bzz: from getUrl if it's there
let getUrlParts = dappConn.getUrl.split('/'); let getUrlParts = dappConn.getUrl.split('/');
getUrlParts = getUrlParts.slice(0, 3); getUrlParts = getUrlParts.slice(0, 3);
let host = canonicalHost(getUrlParts[2].split(':')[0]);
let port = getUrlParts[2].split(':')[1];
getUrlParts[2] = port ? [host, port].join(':') : host;
corsParts.push(getUrlParts.join('/')); corsParts.push(getUrlParts.join('/'));
} }
// in case getUrl wasn't specified, use a built url // in case getUrl wasn't specified, use a built url
@ -59,12 +63,12 @@ class StorageProcessesLauncher {
if(this.blockchainConfig.enabled) { if(this.blockchainConfig.enabled) {
// add our rpc endpoints to CORS // add our rpc endpoints to CORS
if(this.blockchainConfig.rpcHost && this.blockchainConfig.rpcPort){ if(this.blockchainConfig.rpcHost && this.blockchainConfig.rpcPort){
corsParts.push(`http://${this.blockchainConfig.rpcHost}:${this.blockchainConfig.rpcPort}`); corsParts.push(`http://${canonicalHost(this.blockchainConfig.rpcHost)}:${this.blockchainConfig.rpcPort}`);
} }
// add our ws endpoints to CORS // add our ws endpoints to CORS
if(this.blockchainConfig.wsRPC && this.blockchainConfig.wsHost && this.blockchainConfig.wsPort){ if(this.blockchainConfig.wsRPC && this.blockchainConfig.wsHost && this.blockchainConfig.wsPort){
corsParts.push(`ws://${this.blockchainConfig.wsHost}:${this.blockchainConfig.wsPort}`); corsParts.push(`ws://${canonicalHost(this.blockchainConfig.wsHost)}:${this.blockchainConfig.wsPort}`);
} }
} }
return corsParts; return corsParts;

45
lib/utils/host.js Normal file
View File

@ -0,0 +1,45 @@
const isDocker = (() => {
let isDocker;
const hostname = require('os').hostname();
const pattern = new RegExp(
'[0-9]+\:[a-z_-]+\:\/docker\/' + hostname + '[0-9a-z]+', 'i'
);
try {
isDocker = require('child_process')
.execSync(
'cat /proc/self/cgroup',
{stdio: ['ignore', 'pipe', 'ignore']}
)
.toString().match(pattern) !== null;
} catch (e) {
isDocker = false;
}
return isDocker;
})();
const defaultHost = isDocker ? '0.0.0.0' : 'localhost';
// when we're runing in Docker, we can expect (generally, in a development
// scenario) that the user would like to connect to the service in the
// container via the **host's** loopback address, so this helper can be used to
// swap 0.0.0.0 for localhost in code/messages that pertain to client-side
function canonicalHost(host) {
return isDocker && host === '0.0.0.0' ? 'localhost' : host;
}
function dockerHostSwap(host) {
return (isDocker && (host === 'localhost' || host === '127.0.0.1')) ? defaultHost : host;
}
const defaultCorsHost = canonicalHost(defaultHost);
module.exports = {
canonicalHost,
defaultCorsHost,
defaultHost,
dockerHostSwap,
isDocker
};

View File

@ -1,5 +1,6 @@
let http = require('follow-redirects').http; let http = require('follow-redirects').http;
let https = require('follow-redirects').https; let https = require('follow-redirects').https;
const {canonicalHost} = require('./host');
function joinPath() { function joinPath() {
const path = require('path'); const path = require('path');
@ -314,7 +315,7 @@ function buildUrl (protocol, host, port){
function buildUrlFromConfig (configObj){ function buildUrlFromConfig (configObj){
if(!configObj) throw new Error('[utils.buildUrlFromConfig]: config object must cannot be null'); if(!configObj) throw new Error('[utils.buildUrlFromConfig]: config object must cannot be null');
if(!configObj.host) throw new Error('[utils.buildUrlFromConfig]: object must contain a \'host\' property'); if(!configObj.host) throw new Error('[utils.buildUrlFromConfig]: object must contain a \'host\' property');
return this.buildUrl(configObj.protocol, configObj.host, configObj.port); return this.buildUrl(configObj.protocol, canonicalHost(configObj.host), configObj.port);
} }
function compact(array) { function compact(array) {

View File

@ -1,6 +1,7 @@
/*globals describe, it*/ /*globals describe, it*/
const Blockchain = require('../lib/cmds/blockchain/blockchain'); const Blockchain = require('../lib/cmds/blockchain/blockchain');
const constants = require('../lib/constants.json'); const constants = require('../lib/constants.json');
const {defaultHost} = require('../lib/utils/host');
const assert = require('assert'); const assert = require('assert');
@ -19,7 +20,7 @@ describe('embark.Blockchain', function () {
geth_bin: 'geth', geth_bin: 'geth',
datadir: false, datadir: false,
mineWhenNeeded: false, mineWhenNeeded: false,
rpcHost: 'localhost', rpcHost: defaultHost,
rpcPort: 8545, rpcPort: 8545,
rpcApi: ['eth', 'web3', 'net', 'debug'], rpcApi: ['eth', 'web3', 'net', 'debug'],
rpcCorsDomain: false, rpcCorsDomain: false,
@ -33,7 +34,7 @@ describe('embark.Blockchain', function () {
account: {}, account: {},
bootnodes: "", bootnodes: "",
wsApi: ["eth", "web3", "net", "shh", "debug"], wsApi: ["eth", "web3", "net", "shh", "debug"],
wsHost: "localhost", wsHost: defaultHost,
wsOrigins: false, wsOrigins: false,
wsPort: 8546, wsPort: 8546,
wsRPC: true, wsRPC: true,
@ -63,7 +64,7 @@ describe('embark.Blockchain', function () {
geth_bin: 'geth', geth_bin: 'geth',
datadir: '/foo/datadir/', datadir: '/foo/datadir/',
mineWhenNeeded: true, mineWhenNeeded: true,
rpcHost: 'someserver', rpcHost: defaultHost,
rpcPort: 12345, rpcPort: 12345,
rpcApi: ['eth', 'web3', 'net', 'debug'], rpcApi: ['eth', 'web3', 'net', 'debug'],
rpcCorsDomain: true, rpcCorsDomain: true,
@ -77,9 +78,9 @@ describe('embark.Blockchain', function () {
account: {}, account: {},
bootnodes: "", bootnodes: "",
wsApi: ["eth", "web3", "net", "shh", "debug"], wsApi: ["eth", "web3", "net", "shh", "debug"],
wsHost: "localhost", wsHost: defaultHost,
wsOrigins: false, wsOrigins: false,
wsPort: 8546, wsPort: 12346,
wsRPC: true, wsRPC: true,
targetGasLimit: false, targetGasLimit: false,
syncMode: undefined, syncMode: undefined,