From 0c65c9a3745c6a743e0cdaa6d1a64a0e8f816f95 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 13 Sep 2023 06:54:27 -0700 Subject: [PATCH 1/2] Detect and use the new homedir Docker socket on Mac & Linux, if present This is installed by Docker Desktop, and appears to be the preferred socket path in the latest versions. --- lib/modem.js | 35 ++++++++++++++++++++++++++--------- test/modem_test.js | 35 ++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/lib/modem.js b/lib/modem.js index ecf591f..4122d13 100644 --- a/lib/modem.js +++ b/lib/modem.js @@ -9,7 +9,8 @@ var querystring = require('querystring'), utils = require('./utils'), util = require('util'), splitca = require('split-ca'), - isWin = require('os').type() === 'Windows_NT', + os = require('os'), + isWin = os.type() === 'Windows_NT', stream = require('stream'); var defaultOpts = function () { @@ -18,12 +19,12 @@ var defaultOpts = function () { if (!process.env.DOCKER_HOST) { // Windows socket path: //./pipe/docker_engine ( Windows 10 ) - // Linux & Darwin socket path: /var/run/docker.sock - opts.socketPath = isWin ? '//./pipe/docker_engine' : '/var/run/docker.sock'; + // Linux & Darwin socket path is /var/run/docker.sock when running system-wide, + // or $HOME/.docker/run/docker.sock in new Docker Desktop installs. + opts.socketPath = isWin ? '//./pipe/docker_engine' : findDefaultUnixSocket; } else if (process.env.DOCKER_HOST.indexOf('unix://') === 0) { - // Strip off unix://, fall back to default of /var/run/docker.sock if - // unix:// was passed without a path - opts.socketPath = process.env.DOCKER_HOST.substring(7) || '/var/run/docker.sock'; + // Strip off unix://, fall back to default if unix:// was passed without a path + opts.socketPath = process.env.DOCKER_HOST.substring(7) || findDefaultUnixSocket; } else if (process.env.DOCKER_HOST.indexOf('npipe://') === 0) { // Strip off npipe://, fall back to default of //./pipe/docker_engine if // npipe:// was passed without a path @@ -76,6 +77,16 @@ var defaultOpts = function () { return opts; }; +var findDefaultUnixSocket = function () { + return new Promise(function (resolve) { + var userDockerSocket = path.join(os.homedir(), '.docker', 'run', 'docker.sock'); + fs.access(userDockerSocket, function (err) { + if (err) resolve('/var/run/docker.sock'); + else resolve(userDockerSocket); + }) + }); +} + var Modem = function (options) { var optDefaults = defaultOpts(); @@ -220,15 +231,21 @@ Modem.prototype.dial = function (options, callback) { } if (this.socketPath) { - optionsf.socketPath = this.socketPath; + // SocketPath may be a function that can return a promise: + var socketPathValue = typeof this.socketPath === 'function' + ? this.socketPath() : this.socketPath; + Promise.resolve(socketPathValue).then((socketPath) => { + optionsf.socketPath = socketPath; + this.buildRequest(optionsf, options, data, callback); + }); } else { var urlp = url.parse(address); optionsf.hostname = urlp.hostname; optionsf.port = urlp.port; optionsf.path = urlp.path; - } - this.buildRequest(optionsf, options, data, callback); + this.buildRequest(optionsf, options, data, callback); + } }; Modem.prototype.buildRequest = function (options, context, data, callback) { diff --git a/test/modem_test.js b/test/modem_test.js index 57e1855..2e4c77e 100644 --- a/test/modem_test.js +++ b/test/modem_test.js @@ -1,7 +1,20 @@ var assert = require('assert'); +var path = require('path'); +var os = require('os'); var http = require('http'); var Modem = require('../lib/modem'); -var defaultSocketPath = require('os').type() === 'Windows_NT' ? '//./pipe/docker_engine' : '/var/run/docker.sock'; + +var unixDefaultSocketPaths = ['/var/run/docker.sock', path.join(os.homedir(), '.docker/run/docker.sock')] +var defaultSocketPaths = os.type() === 'Windows_NT' ? ['//./pipe/docker_engine'] : unixDefaultSocketPaths; + +function resolveSocketPath(socketPathField) { + if (typeof socketPathField === 'function') { + return Promise.resolve(socketPathField()); + } else { + // Return it as a promise, just for consistency + return Promise.resolve(socketPathField); + } +} describe('Modem', function () { beforeEach(function () { @@ -10,8 +23,11 @@ describe('Modem', function () { it('should default to default socket path', function () { var modem = new Modem(); - assert.ok(modem.socketPath); - assert.strictEqual(modem.socketPath, defaultSocketPath); + + return resolveSocketPath(modem.socketPath).then((socketPath) => { + assert.ok(socketPath); + assert.ok(defaultSocketPaths.includes(socketPath)); + }); }); it('should use specific cert, key and ca', function () { @@ -50,9 +66,12 @@ describe('Modem', function () { headers: customHeaders }); assert.ok(modem.headers); - assert.ok(modem.socketPath); - assert.strictEqual(modem.socketPath, defaultSocketPath); assert.strictEqual(modem.headers, customHeaders); + + return resolveSocketPath(modem.socketPath).then((socketPath) => { + assert.ok(socketPath); + assert.ok(defaultSocketPaths.includes(socketPath)); + }); }); it('should allow DOCKER_HOST=unix:///path/to/docker.sock', function () { @@ -67,8 +86,10 @@ describe('Modem', function () { process.env.DOCKER_HOST = 'unix://'; var modem = new Modem(); - assert.ok(modem.socketPath); - assert.strictEqual(modem.socketPath, '/var/run/docker.sock'); + return resolveSocketPath(modem.socketPath).then((socketPath) => { + assert.ok(socketPath); + assert.ok(unixDefaultSocketPaths.includes(socketPath)); + }); }); it('should interpret DOCKER_HOST=tcp://N.N.N.N:2376 as https', function () { From a04e0ef0b4ad82f9a852f5a435e40d740e028371 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 13 Sep 2023 07:21:34 -0700 Subject: [PATCH 2/2] Add getSocketPath method to easily read the detected socket path --- lib/modem.js | 13 ++++++++++--- test/modem_test.js | 15 +++------------ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/modem.js b/lib/modem.js index 4122d13..9062eb7 100644 --- a/lib/modem.js +++ b/lib/modem.js @@ -232,9 +232,7 @@ Modem.prototype.dial = function (options, callback) { if (this.socketPath) { // SocketPath may be a function that can return a promise: - var socketPathValue = typeof this.socketPath === 'function' - ? this.socketPath() : this.socketPath; - Promise.resolve(socketPathValue).then((socketPath) => { + this.getSocketPath().then((socketPath) => { optionsf.socketPath = socketPath; this.buildRequest(optionsf, options, data, callback); }); @@ -248,6 +246,15 @@ Modem.prototype.dial = function (options, callback) { } }; +Modem.prototype.getSocketPath = function () { + if (!this.socketPath) return; + + var socketPathValue = typeof this.socketPath === 'function' + ? this.socketPath() : this.socketPath; + + return Promise.resolve(socketPathValue); +} + Modem.prototype.buildRequest = function (options, context, data, callback) { var self = this; var connectionTimeoutTimer; diff --git a/test/modem_test.js b/test/modem_test.js index 2e4c77e..d12e5a4 100644 --- a/test/modem_test.js +++ b/test/modem_test.js @@ -7,15 +7,6 @@ var Modem = require('../lib/modem'); var unixDefaultSocketPaths = ['/var/run/docker.sock', path.join(os.homedir(), '.docker/run/docker.sock')] var defaultSocketPaths = os.type() === 'Windows_NT' ? ['//./pipe/docker_engine'] : unixDefaultSocketPaths; -function resolveSocketPath(socketPathField) { - if (typeof socketPathField === 'function') { - return Promise.resolve(socketPathField()); - } else { - // Return it as a promise, just for consistency - return Promise.resolve(socketPathField); - } -} - describe('Modem', function () { beforeEach(function () { delete process.env.DOCKER_HOST; @@ -24,7 +15,7 @@ describe('Modem', function () { it('should default to default socket path', function () { var modem = new Modem(); - return resolveSocketPath(modem.socketPath).then((socketPath) => { + return modem.getSocketPath().then((socketPath) => { assert.ok(socketPath); assert.ok(defaultSocketPaths.includes(socketPath)); }); @@ -68,7 +59,7 @@ describe('Modem', function () { assert.ok(modem.headers); assert.strictEqual(modem.headers, customHeaders); - return resolveSocketPath(modem.socketPath).then((socketPath) => { + return modem.getSocketPath().then((socketPath) => { assert.ok(socketPath); assert.ok(defaultSocketPaths.includes(socketPath)); }); @@ -86,7 +77,7 @@ describe('Modem', function () { process.env.DOCKER_HOST = 'unix://'; var modem = new Modem(); - return resolveSocketPath(modem.socketPath).then((socketPath) => { + return modem.getSocketPath().then((socketPath) => { assert.ok(socketPath); assert.ok(unixDefaultSocketPaths.includes(socketPath)); });