I want to connect to Docker API with Websockets, however, in any container it just gives me 403 Forbidden Error. I do not know what I am doing wrong, there is not enough documentation about it, but here is my code:
var docker = require('docker.io')({
socketPath: false,
host: "http://127.0.0.1",
port: "4500"
});
var WebSocket = require('ws');
var opts = {
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"Tty": true,
"OpenStdin": true,
"Cmd": [
"/bin/bash"
],
"Image": "ubuntu"
};
docker.containers.create(opts, function(err, result) {
if (!err) {
var containerId = result.Id;
console.log("Container", containerId, "created");
docker.containers.start(containerId, function(err, result) {
console.log(result);
var ws = new WebSocket('ws://127.0.0.1:4500/v1.7/containers/' + containerId + '/attach/ws?logs=1&stderr=1&stdout=1');
ws.on("open", function() {
console.log("ok, open");
});
ws.on("message", function(msg) {
console.log("msg", msg);
});
ws.on("error", function(msg) {
console.log("error", msg);
});
});
} else {
console.log(err);
}
});
The output it produces is:
Container ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922 created
error [Error: unexpected server response (403)]
But I see the Docker daemon output as follows:
Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
[/var/lib/docker|f99d0d11] -job create() = OK (0)
2014/04/16 23:04:09 POST http://127.0.0.1:4500/v1.7/containers/ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922/start
[error] common.go:41 Error parsing media type: error: mime: no media type
[/var/lib/docker|f99d0d11] +job start(ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922)
[/var/lib/docker|f99d0d11] +job allocate_interface(ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922)
[/var/lib/docker|f99d0d11] -job allocate_interface(ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922) = OK (0)
[/var/lib/docker|f99d0d11] -job start(ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922) = OK (0)
2014/04/16 23:04:09 GET /v1.7/containers/ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922/attach/ws
[/var/lib/docker|f99d0d11] +job inspect(ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922, container)
[/var/lib/docker|f99d0d11] -job inspect(ceeef5eb34acf06dad7d6fea01dd71d9b0283c63b14bc52d49585aa379ec4922, container) = OK (0)
As it can be seen requests comes to Daemon but there is no indication why it gives a 403 Forbidden error.
It seems that I needed to change 127.0.0.1 to localhost and it magically worked.
Related
You can see for yourself that the request hangs:
curl "http://europasprak.com:9001/socket.io/?EIO=4&transport=polling"
It also hangs when sending the request from the server machine itself:
curl "http://localhost:9001/socket.io/?EIO=4&transport=polling"
I'm trying to create a socket.io server following the documentation.
I have the NodeJS socket server:
var http = require('http');
var socketio = require('socket.io');
var httpServer = http.createServer(utils.httpHandler);
httpServer.listen(config.socketio.port, function() {
console.log('The NodeJS HTTP server [port: ' + config.socketio.port + '] is listening...');
});
Using the DEBUG variable to start the server as in:
DEBUG=socket* node /usr/local/learnintouch/engine/api/js/socket/elearning-server.js 2>&1 >> /usr/local/learnintouch/logs/nodejs.log
shows:
socket.io:server creating engine.io instance with opts {"cors":{"origin":"*"},"path":"/socket.io"} +2ms
socket.io:server attaching client serving req handler +5ms
socket.io:server initializing namespace / +1ms
socket.io:server initializing namespace /elearning +10ms
The NodeJS log shows:
The NodeJS HTTP server [port: 9001] is listening...
The server object is:
{
io: Server {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
_nsps: Map { '/' => [Namespace] },
parentNsps: Map {},
_path: '/socket.io',
clientPathRegex: /^\/socket\.io\/socket\.io(\.min|\.msgpack\.min)?\.js(\.map)?$/,
_connectTimeout: 45000,
_serveClient: true,
_parser: {
protocol: 5,
PacketType: [Object],
Encoder: [Function: Encoder],
Decoder: [Function: Decoder]
},
encoder: Encoder {},
_adapter: [Function],
sockets: Namespace {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
sockets: Map {},
_fns: [Array],
_ids: 0,
server: [Circular],
name: '/',
adapter: [RedisAdapter],
[Symbol(kCapture)]: false
},
opts: { cors: [Object] },
[Symbol(kCapture)]: false
}
}
The connection is then handled like this:
module.exports.io = socketio(httpsServer, {
cors: {
origin: '*',
}
});
module.exports.io.adapter(ioredis({ host: config.redis.hostname, port: config.redis.port }));
var redisClient = redis.createClient(config.redis.port, config.redis.hostname);
module.exports.io.use(function (socket, handler) {
console.log('The namespace middleware is registered');
console.log(socket.request.headers.cookie);
if (socket.request.headers.cookie) {
socket.request.cookies = cookie.parse(decodeURIComponent(socket.request.headers.cookie));
socket.request.sessionID = socket.request.cookies['PHPSESSID'];
socket.request.socketSessionId = socket.request.cookies['socketSessionId'];
console.log("Authorization attempt with sessionID: " + socket.request.sessionID + " and socketSessionId: " + socket.request.socketSessionId);
redisClient.get("PHPREDIS_SESSION:" + socket.request.sessionID, function (error, reply) {
if (error) {
console.log("The redis client had an error: " + error);
return handler(new Error('The connection was refused because the redis client had an error.'));
} else if (!reply) {
console.log('The connection was refused because the redis client did not find the sessionID.');
return handler(new Error('The connection was refused because the redis client did not find the sessionID.'));
} else {
var redisSocketSessionId = utils.getRedisValue(reply, "socketSessionId");
if ('undefined' == typeof socket.request.socketSessionId || redisSocketSessionId != socket.request.socketSessionId) {
console.log('The connection was refused because the socketSessionId was invalid.');
return handler(new Error('The connection was refused because the socketSessionId was invalid.'));
} else {
console.log('The connection was granted.');
handler();
}
}
});
} else {
console.log('The connection was refused because no cookie was transmitted.');
return handler(new Error('The connection was refused because no cookie was transmitted.'));
}
});
The client connection:
<script type="text/javascript">
var elearningSocket;
$(function() {
if ('undefined' != typeof io && 'undefined' == typeof elearningSocket) {
console.log("Creating a socket on //dev.learnintouch.com:9001/elearning");
elearningSocket = io.connect('//dev.learnintouch.com:9001/elearning', { reconnect: true, rejectUnauthorized: false });
}
if ('undefined' != typeof elearningSocket) {
console.log("A socket on //dev.learnintouch.com:9001/elearning has been created");
elearningSocket.on('connect', function() {
console.log("The elearning namespace socket connected");
elearningSocket.emit('watchLiveCopilot', {'elearningSubscriptionId': '63', 'elearningClassId': '7'});
});
elearningSocket.on('postLogin', function(data) {
isAdmin = data.admin;
});
elearningSocket.on('message', function(message) {
console.log(message);
});
}
});
</script>
And the Chrome browser console:
Creating a socket on //dev.learnintouch.com:9001/elearning
A socket on //dev.learnintouch.com:9001/elearning has been created
But when sending a client connection, the log never shows the The namespace middleware is registered message.
Versions:
http#0.0.1-security
https#1.0.0
socket.io#4.1.3
cors#2.8.5
redis#3.1.2
socket.io-redis#6.1.1
connect#3.7.0
cookie#0.4.1
lodash#4.17.21
It looks like the connection cannot be established.
After a while the browser console shows an ERR_EMPTY_RESPONSE message as in:
socket.io.min.js:6 GET http://dev.learnintouch.com:9001/socket.io/?EIO=4&transport=polling&t=NbGNn6V net::ERR_EMPTY_RESPONSE
But the NodeJS socket server seems to be listening:
netstat -l | grep 9001
tcp6 0 0 [::]:9001 [::]:* LISTEN
The NodeJS socket server is not reachable.
But the firewall seems not to be the issue:
sudo ufw status verbose
Status: active
To Action From
-- ------ ----
9001 ALLOW IN Anywhere
The error can be seen live at
http://www.europasprak.com/elearning/subscription/2938/course
by first logging at
http://www.europasprak.com/engine/modules/user/login.php
with using the user demo#demo.com with the demo password.
UPDATE: I could solve the issue. It related to a handler preventing the connection from being established.
When changing the following:
module.exports.io.use((socket, handler) => {
to the following:
module.exports.io.of('/elearning').use((socket, handler) => {
the connection could then be done.
you need to determine whether the socket.io connection is successful, and then add events such as cores, adapters, events etc...to track down the problem step by step.
judging from the error report you provided above, socket.io was not established successfully.
I am trying to run elastic search on my express/nodejs app on ubuntu 17.10. But somehow, it is giving the error as shown below:
Error: Request error, retrying
HEAD http://localhost:9200/ => connect ECONNREFUSED 127.0.0.1:9200
My code for that is as shown below:
const connectElasticSearchClient = () => {
client = new elasticsearch.Client({
hosts: ['localhost:9200'],
maxRetries: 10,
keepAlive: true,
maxSockets: 10,
minSockets: 10
});
client.ping({
requestTimeout: 300000,
}, function (error) {
if (error) {
console.error('elasticsearch cluster is down!' + error);
} else {
console.log('Everything is ok');
}
});
};
I am trying to run it on node version 8.11.1. The version of elasticsearch npm package is 13.3.1.
Let's say I have a list of hostnames and ports, not all of which are HTTP related.
var config = {
"checks": [
{
"name": "NPM",
"hostname": "npmjs.com",
"port": 80
},
{
"name": "AWS",
"hostname": "aws.amazon.com",
"port": 443
},
{
"name": "RabbitMQ",
"hostname": "merry-butterfly.rmq.cloudamqp.com",
"port": 5671
}
]
}
What is an effective way to test that each of these services can be reached? My first thoughts were to use a typical telnet-like approach, I did this:
var telnet = require('telnet-client')
config.checks.forEach(function(check) {
var connection = new telnet()
var params = {
host: check.hostname,
port: check.port,
negotiationMandatory: false
}
connection.on('connect', function() {
connection.send('GET /', {
ors: '\r\n',
waitfor: '\n'
}, function(err, data) {
console.log(err, data);
connection.end()
})
})
connection.connect(params)
results.push(result);
});
The above seems to work, but I'm actually not sure what data to send to each individual services to get back a response that suggests the service is "reachable", I don't need to auth or do any operations with the service, just check that it can be reached. Additionally it raises an exception if the DNS is unreachable:
Error: getaddrinfo ENOTFOUND merry-butterfly.rmq.cloudamqp.com/api merry-butterfly.rmq.cloudamqp.com/api:443
What would be the appropriate way to handle the errors, and async test each of the entries in the list of "checks"?
Ping the host.
https://www.npmjs.com/package/ping
For example:
var ping = require('ping');
var hosts = ['192.168.1.1', 'google.com', 'yahoo.com'];
hosts.forEach(function(host){
ping.sys.probe(host, function(isAlive){
var msg = isAlive ? 'host ' + host + ' is alive' : 'host ' + host + ' is dead';
console.log(msg);
});
});
I'm writing a node program that uses dockernode as the Docker client. The program creates a container with a volume that is bound to a directory on the host when the container is started. One started, I attempt to print the contents of the shared volume to prove that it's working properly. However, I keep getting (ls: /tmp/app: No such file or directory.
Here is my code...
var Docker = require('dockerode'),
docker = new Docker(),
mkdirp = require('mkdirp'),
volume = (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE) + '/' + Date.now();
function handleError(action, err) {
if (err) {
console.error('error while ' + action + '...');
console.error(err);
}
}
mkdirp.sync(volume);
docker.createContainer({
Image: 'ubuntu',
Volumes: {
'/tmp/app': {}
}
}, function(err, container) {
handleError('building', err);
container.start({
Binds: [volume + ':/tmp/app']
}, function(err, data) {
handleError('starting', err);
container.exec({
AttachStdout: true,
AttachStderr: true,
Tty: false,
Cmd: ['/bin/ls', '/tmp/app']
}, function(err, exec) {
handleError('executing `ls /tmp/app`', err);
exec.start(function(err, stream) {
handleError('handling response from `ls /tmp/app`', err);
stream.setEncoding('utf8');
stream.pipe(process.stdout);
});
});
});
});
I've succeeded by doing this without exec, where I create the container, attach to it, start it with the ls command, wait for it to finish, and then kill it and remove it. But I'm looking to use exec so I can issue multiple commands once the container is running. I've been trying to piece this together from the examples in the dockerode library and the Docker remote API documentation. I just don't know where I'm going wrong.
For reference, here is the code without exec...
docker.createContainer({
Image: 'ubuntu',
Cmd: ['/bin/ls', '/tmp/app'],
Volumes: {
'/tmp/app': {}
}
}, function(err, container) {
console.log('attaching to... ' + container.id);
container.attach({stream: true, stdout: true, stderr: true, tty: true}, function(err, stream) {
handleError('attaching', err);
stream.pipe(process.stdout);
console.log('starting... ' + container.id);
container.start({
Binds: [volume + ':/tmp/app']
}, function(err, data) {
handleError('starting', err);
});
container.wait(function(err, data) {
handleError('waiting', err);
console.log('killing... ' + container.id);
container.kill(function(err, data) {
handleError('killing', err);
console.log('removing... ' + container.id);
container.remove(function(err, data) {
handleError('removing', err);
});
});
});
});
});
I had struggled with same issue for some time,but I found solution. It seems that Remote API do not accept command with arguments as one string, but you have to split each argument as new token in Cmd property array; for example with gcc:
"Cmd":["/bin/bash","-c","gcc -Wall -std=c99 hello.c -o hello.bin"]
After this modification it works correctly.
Official documentation could be better for Remote API configuration.
I'm trying to get a persistent connection from my socket.io-client (running on Node.js) to a remote websocket. I do not have control over the remote socket, and sometimes it can go down entirely. I would like to attempt to reconnect() whenever an error or disconnect occurs. In the following example, I'm trying to test the case where the remote host is refusing a connection. In this case, I would like to attempt to reconnect after 1 second. It calls a second time, and exits.
Here's the code:
var events = require('events'),
util = require('util'),
io = require('socket.io-client'),
url = "ws://localhost:12345", // intentionally an unreachable URL
socketOptions = {
"transports" : [ "websocket" ],
"try multiple transports" : false,
"reconnect" : false,
"connect timeout" : 5000
};
// The goal is to have this socket attempt to connect forever
// I would like to do it without the built in reconnects, as these
// are somewhat unreliable (reconnect* events not always firing)
function Test(){
var self = this;
events.EventEmitter.call(self);
var socket;
function reconnect(){
setTimeout(go, 1000);
}
function go(){
console.log("connecting to", url, socketOptions);
socket = io.connect(url, socketOptions);
socket.on('connect', function(){
console.log("connected! wat.");
});
socket.on('error', function(err){
console.log("socket.io-client 'error'", err);
reconnect();
});
socket.on('connect_failed', function(){
console.log("socket.io-client 'connect_failed'");
reconnect();
});
socket.on('disconnect', function(){
console.log("socket.io-client 'disconnect'");
reconnect();
});
}
go();
}
util.inherits(Test, events.EventEmitter);
var test = new Test();
process.on('exit', function(){
console.log("this should never end");
});
When running it under node 0.11.0 I get the following:
$ node socketio_websocket.js
connecting to ws://localhost:12345 { transports: [ 'websocket' ],
'try multiple transports': false,
reconnect: false,
'connect timeout': 5000 }
socket.io-client 'error' Error: connect ECONNREFUSED
at errnoException (net.js:878:11)
at Object.afterConnect [as oncomplete] (net.js:869:19)
connecting to ws://localhost:12345 { transports: [ 'websocket' ],
'try multiple transports': false,
reconnect: false,
'connect timeout': 5000 }
this should never end
The ECONNREFUSED is an exception you don't manage.
Try with this:
process.on('uncaughtException', function(err) {
if(err.code == 'ECONNREFUSED'){
reconnect();
}
}
Edit
Modify the options like this:
socketOptions = {
"transports" : [ "websocket" ],
"try multiple transports" : false,
"reconnect" : false,
'force new connection': true, // <-- Add this!
"connect timeout" : 5000
};
and the reconnect function (look in the comments for the explanation)
function reconnect(){
socket.removeAllListeners();
setTimeout(go, 1000);
}
Probably socket.io reuse the same connection without creating a new one, forcing it the app works